Write and Read a plist in swift with simple data

前端 未结 3 667
野性不改
野性不改 2020-12-15 14:38

i\'m trying to understand how to save a simple value, an integer, in a plist. but i\'m finding on the net only solution for save dictionary and array and i don\'t understand

相关标签:
3条回答
  • 2020-12-15 14:53

    Update for Swift 4

    I have created SwiftyPlistManager. Take a look at it on GiHub and follow these video instructions:

    https://www.youtube.com/playlist?list=PL_csAAO9PQ8bKg79CX5PEfn886SMMDj3j

    Update for Swift 3.1

    let BedroomFloorKey = "BedroomFloor"
    let BedroomWallKey = "BedroomWall"
    var bedroomFloorID: Any = 101
    var bedroomWallID: Any = 101
    
    func loadGameData() {
    
      // getting path to GameData.plist
      let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
      let documentsDirectory = paths.object(at: 0) as! NSString
      let path = documentsDirectory.appendingPathComponent("GameData.plist")
    
      let fileManager = FileManager.default
    
      //check if file exists
      if !fileManager.fileExists(atPath: path) {
    
        guard let bundlePath = Bundle.main.path(forResource: "GameData", ofType: "plist") else { return }
    
        do {
          try fileManager.copyItem(atPath: bundlePath, toPath: path)
        } catch let error as NSError {
          print("Unable to copy file. ERROR: \(error.localizedDescription)")
        }
      }
    
      let resultDictionary = NSMutableDictionary(contentsOfFile: path)
      print("Loaded GameData.plist file is --> \(resultDictionary?.description ?? "")")
    
      let myDict = NSDictionary(contentsOfFile: path)
    
      if let dict = myDict {
        //loading values
        bedroomFloorID = dict.object(forKey: BedroomFloorKey)!
        bedroomWallID = dict.object(forKey: BedroomWallKey)!
        //...
      } else {
        print("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
      }
    }
    
    func saveGameData() {
    
      let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
      let documentsDirectory = paths.object(at: 0) as! NSString
      let path = documentsDirectory.appendingPathComponent("GameData.plist")
    
      let dict: NSMutableDictionary = ["XInitializerItem": "DoNotEverChangeMe"]
      //saving values
      dict.setObject(bedroomFloorID, forKey: BedroomFloorKey as NSCopying)
      dict.setObject(bedroomWallID, forKey: BedroomWallKey as NSCopying)
      //...
    
      //writing to GameData.plist
      dict.write(toFile: path, atomically: false)
    
      let resultDictionary = NSMutableDictionary(contentsOfFile: path)
      print("Saved GameData.plist file is --> \(resultDictionary?.description ?? "")")
    }
    

    Here's what I use to read/write a plist file in swift:

    let BedroomFloorKey = "BedroomFloor"
    let BedroomWallKey = "BedroomWall"
    var bedroomFloorID: AnyObject = 101
    var bedroomWallID: AnyObject = 101
    
    func loadGameData() {
    
    // getting path to GameData.plist
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
    let documentsDirectory = paths[0] as String
    let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")
    
    let fileManager = NSFileManager.defaultManager()
    
    //check if file exists
    if(!fileManager.fileExistsAtPath(path)) {
      // If it doesn't, copy it from the default file in the Bundle
      if let bundlePath = NSBundle.mainBundle().pathForResource("GameData", ofType: "plist") {
    
        let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
        println("Bundle GameData.plist file is --> \(resultDictionary?.description)")
    
        fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)
        println("copy")
      } else {
        println("GameData.plist not found. Please, make sure it is part of the bundle.")
      }
    } else {
      println("GameData.plist already exits at path.")
      // use this to delete file from documents directory
      //fileManager.removeItemAtPath(path, error: nil)
    }
    
    let resultDictionary = NSMutableDictionary(contentsOfFile: path)
    println("Loaded GameData.plist file is --> \(resultDictionary?.description)")
    
    var myDict = NSDictionary(contentsOfFile: path)
    
    if let dict = myDict {
      //loading values
      bedroomFloorID = dict.objectForKey(BedroomFloorKey)!
      bedroomWallID = dict.objectForKey(BedroomWallKey)!
      //...
    } else {
      println("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
    }
    }
    
    func saveGameData() {
    
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
    let documentsDirectory = paths.objectAtIndex(0) as NSString
    let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")
    
    var dict: NSMutableDictionary = ["XInitializerItem": "DoNotEverChangeMe"]
    //saving values
    dict.setObject(bedroomFloorID, forKey: BedroomFloorKey)
    dict.setObject(bedroomWallID, forKey: BedroomWallKey)
    //...
    
    //writing to GameData.plist
    dict.writeToFile(path, atomically: false)
    
    let resultDictionary = NSMutableDictionary(contentsOfFile: path)
    println("Saved GameData.plist file is --> \(resultDictionary?.description)")
    }
    

    The plist file is this:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>BedroomFloor</key>
        <integer>101</integer>
        <key>BedroomWall</key>
        <integer>101</integer>
        <key>XInitializerItem</key>
        <string>DoNotEverChangeMe</string>
    </dict>
    </plist>
    
    0 讨论(0)
  • 2020-12-15 14:55

    You can't have anything other than an array or dictionary as the root object in a plist. This is because plist files are essentially special xml files so when you are trying to read the file you ask for object at key or object at index, otherwise you have no means of obtaining your data. Also, when inserting numbers into a plist, you must wrap them in the NSNumber class. To save your objects, check out this answer.

    0 讨论(0)
  • 2020-12-15 15:17

    My variant function to read and write .plist on swift, tested on device.

    Exapmle:
    var dataVersion = readPlist("Options", key: "dataVersion")
    writePlist("Options", key: "dataVersion", data: 1.23)

    Function:

    func readPlist(namePlist: String, key: String) -> AnyObject{
        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
        let documentsDirectory = paths.objectAtIndex(0) as! NSString
        let path = documentsDirectory.stringByAppendingPathComponent(namePlist+".plist")
    
        var output:AnyObject = false
    
        if let dict = NSMutableDictionary(contentsOfFile: path){
            output = dict.objectForKey(key)!
        }else{
            if let privPath = NSBundle.mainBundle().pathForResource(namePlist, ofType: "plist"){
                if let dict = NSMutableDictionary(contentsOfFile: privPath){
                    output = dict.objectForKey(key)!
                }else{
                    output = false
                    println("error_read")
                }
            }else{
                output = false
                println("error_read")
            }
        }
        return output
    }
    func writePlist(namePlist: String, key: String, data: AnyObject){
        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
        let documentsDirectory = paths.objectAtIndex(0) as! NSString
        let path = documentsDirectory.stringByAppendingPathComponent(namePlist+".plist")
    
        if let dict = NSMutableDictionary(contentsOfFile: path){
            dict.setObject(data, forKey: key)
            if dict.writeToFile(path, atomically: true){
                println("plist_write")
            }else{
                println("plist_write_error")
            }
        }else{
            if let privPath = NSBundle.mainBundle().pathForResource(namePlist, ofType: "plist"){
                if let dict = NSMutableDictionary(contentsOfFile: privPath){
                    dict.setObject(data, forKey: key)
                    if dict.writeToFile(path, atomically: true){
                        println("plist_write")
                    }else{
                        println("plist_write_error")
                    }
                }else{
                    println("plist_write")
                }
            }else{
                println("error_find_plist")
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题