Save Data to .plist File in Swift
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 documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
var path : NSString = documentsDirectory.stringByAppendingPathComponent("data.plist")
var data : NSMutableDictionary = NSMutableDictionary(contentsOfFile: path)
data.setObject(self.object, forKey: "key")
data.writeToFile(path, atomically: true)
Edit: I've heard that the best way to do this is write to the documents directory, so my question would be how should I write to a file in that directory?
Solution 1:
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)
Solution 2:
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
Solution 3:
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)
}
Solution 4:
Use writeToFile:options:error: and see what the error says:
var error: NSError?
var bytes = NSKeyedArchiver.archivedDataWithRootObject(data)
if !bytes.writeToFile(path, options: nil, error: &error) {
if let actualError = error {
println(actualError)
}
}
Solution 5:
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")
}