I am trying to save data to a plist file in swift, but the data isn\'t showing up as it was saved when the plist is read. This is the code I was using.
var
struct Plist {
enum PlistError: ErrorType {
case FileNotWritten
case FileDoesNotExist
}
let name:String
var sourcePath:String? {
guard let path = NSBundle.mainBundle().pathForResource(name, ofType: "plist") else { return .None }
return path
}
var destPath:String? {
guard sourcePath != .None else { return .None }
let dir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
return (dir as NSString).stringByAppendingPathComponent("\(name).plist")
}
init?(name:String) {
self.name = name
let fileManager = NSFileManager.defaultManager()
guard let source = sourcePath else { return nil }
guard let destination = destPath else { return nil }
guard fileManager.fileExistsAtPath(source) else { return nil }
if !fileManager.fileExistsAtPath(destination) {
do {
try fileManager.copyItemAtPath(source, toPath: destination)
} catch let error as NSError {
print("Unable to copy file. ERROR: \(error.localizedDescription)")
return nil
}
}
}
func getValuesInPlistFile() -> NSDictionary?{
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(destPath!) {
guard let dict = NSDictionary(contentsOfFile: destPath!) else { return .None }
return dict
} else {
return .None
}
}
func getMutablePlistFile() -> NSMutableDictionary?{
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(destPath!) {
guard let dict = NSMutableDictionary(contentsOfFile: destPath!) else { return .None }
return dict
} else {
return .None
}
}
func addValuesToPlistFile(dictionary:NSDictionary) throws {
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(destPath!) {
if !dictionary.writeToFile(destPath!, atomically: false) {
print("File not written successfully")
throw PlistError.FileNotWritten
}
} else {
throw PlistError.FileDoesNotExist
}
}
}
Now, implement below in your view controller.
if let plist = Plist(name: "plist file name") {
let dict = plist.getMutablePlistFile()!
dict["key"] = value
do {
try plist.addValuesToPlistFile(dict)
} catch {
print(error)
}
print(plist.getValuesInPlistFile())
} else {
print("Unable to get Plist")
}
From your Information Property List
Key
Privacy - Photo Library Additions Usage Description
Type
String
Value
"Your App Name" would like to access the photo gallery to manage your profile picture
Swift 3:
func loadData() {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let documentDirectory = paths[0] as! String
let path = documentDirectory.appending("myData.plist")
let fileManager = FileManager.default
if(!fileManager.fileExists(atPath: path)){
if let bundlePath = Bundle.main.path(forResource: "myData", ofType: "plist"){
let result = NSMutableDictionary(contentsOfFile: bundlePath)
print("Bundle file myData.plist is -> \(result?.description)")
do{
try fileManager.copyItem(atPath: bundlePath, toPath: path)
}catch{
print("copy failure.")
}
}else{
print("file myData.plist not found.")
}
}else{
print("file myData.plist already exits at path.")
}
let resultDictionary = NSMutableDictionary(contentsOfFile: path)
print("load myData.plist is ->\(resultDictionary?.description)")
let myDict = NSDictionary(contentsOfFile: path)
if let dict = myDict{
myItemValue = dict.object(forKey: myItemKey) as! String?
txtValue.text = myItemValue
}else{
print("load failure.")
}
}
Read and Write plist file in swift
Apparently the file is not in a writable location, so I created it in the documents directory.
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var path = paths.stringByAppendingPathComponent("data.plist")
var fileManager = NSFileManager.defaultManager()
if (!(fileManager.fileExistsAtPath(path)))
{
var bundle : NSString = NSBundle.mainBundle().pathForResource("data", ofType: "plist")
fileManager.copyItemAtPath(bundle, toPath: path, error:nil)
}
data.setObject(object, forKey: "object")
data.writeToFile(path, atomically: true)
Then, it has to be read from the documents directory.
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var path = paths.stringByAppendingPathComponent("data.plist")
let save = NSDictionary(contentsOfFile: path)
Check in Xcode 10 swift 4.1
//TODO: for wtite in .plist file
let docsBaseURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let customPlistURL = docsBaseURL.appendingPathComponent("custom.plist")
print(customPlistURL.absoluteString)
let dic:[String:Any] = ["key":"val"]
// Swift Dictionary To Data.
do {
let data = try PropertyListSerialization.data(fromPropertyList: dic, format: PropertyListSerialization.PropertyListFormat.binary, options: 0)
do {
try data.write(to: customPlistURL, options: .atomic)
print("Successfully write")
}catch (let err){
print(err.localizedDescription)
}
}catch (let err){
print(err.localizedDescription)
}
updated swift code of Rebeloper:
let BedroomFloorKey = "BedroomFloor"
let BedroomWallKey = "BedroomWall"
var bedroomFloorID: AnyObject = 101
var bedroomWallID: AnyObject = 101
func saveGameData()
{
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as! NSString
let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")
let 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)
print("Saved GameData.plist file is --> \(resultDictionary?.description)")
self.loadGameData()
}//eom
func loadGameData() {
// getting path to GameData.plist
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths[0] as! NSString
let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")
// 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)
print("Bundle GameData.plist file is --> \(resultDictionary?.description)")
do
{
try fileManager.copyItemAtPath(bundlePath, toPath: path)
print("copy")
}
catch _
{
print("error failed loading data")
}
}
else
{
print("GameData.plist not found. Please, make sure it is part of the bundle.")
}
}
else
{
print("GameData.plist already exits at path.")
// use this to delete file from documents directory
//fileManager.removeItemAtPath(path, error: nil)
}
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.objectForKey(BedroomFloorKey)!
bedroomWallID = dict.objectForKey(BedroomWallKey)!
//...
}
else
{
print("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
}
}//eom