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 what i can change to work it only for an integer.
this is the code for the moment...
var musicalChoice = 1
var musicString : String = "5"
override func viewDidLoad() {
super.viewDidLoad()
musicString = String(musicalChoice)}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func writePlist() {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as NSString
let path = documentsDirectory.stringByAppendingPathComponent("Preferences.plist")
musicString.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error:nil )
}
func readPlist() {
}
Update for Swift 4
I have created SwiftyPlistManager. Take a look at it on GiHub and follow these video instructions:
![](https://www.manongdao.com/static/images/pcload.jpg)
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>
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.
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")
}
}
}