I'm retrieving a plist
file, updating it, and writing it to disk.
1) Retrieval
func pListURL() -> URL? {
guard let result = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("somePlist.plist") else { return nil }
return result
}
2) Update
var data: [String: Int] = [:]
if let url = pListURL() {
do {
let dataContent = try Data(contentsOf: url)
if let dict = try PropertyListSerialization.propertyList(from: dataContent, format: nil) as? [String: Int] {
data = dict
}
} catch {
print(error)
}
}
// update code
3) Write
if let path = pListURL() {
do {
let plistData = try PropertyListSerialization.data(fromPropertyList: data, format: .xml, options: 0)
try plistData.write(to: path)
} catch {
print(error)
}
}
The odd thing is I get an error that says:
The file “somePlist.plist” couldn’t be opened because there is no such file.
even though when I check the plist
, it's actually properly created and updated as it should be. As far as I know, the create
parameter of FileManager.default.url(for:in:appropriateFor:create: ) ensures that it "creates the directory if it does not already exist", which means somePlist.plist
is created if plist
doesn't exist already.
As far as I know, the create parameter of FileManager.default.url(for:in:appropriateFor:create: ) ensures that it "creates the directory if it does not already exist", which means somePlist.plist is created if plist doesn't exist already.
No, it means the directory is created but the file is not created.
In the update part ignore the couldn’t be opened
error and write the (new) data to disk or check if the file exists with fileExists(atPath
.
And you can declare the return value in pListURL
as non-optional. It's guaranteed that the folder Documents
exists
func pListURL() -> URL {
return try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("somePlist.plist")
}
Update:
These are reliable versions of update
and write
func update(dictionary: [String:Int]) {
let url = pListURL()
guard FileManager.default.fileExists(atPath: url.path) else { write(dictionary: dictionary); return }
do {
let dataContent = try Data(contentsOf: url)
if var dict = try PropertyListSerialization.propertyList(from: dataContent, format: nil) as? [String: Int] {
for (key, value) in dictionary {
dict.updateValue(value, forKey: key)
}
write(dictionary: dict)
} else {
write(dictionary: dictionary)
}
} catch {
print(error)
}
}
func write(dictionary: [String:Int]) {
let url = pListURL()
do {
let plistData = try PropertyListSerialization.data(fromPropertyList: dictionary, format: .xml, options: 0)
try plistData.write(to: url)
} catch {
print(error)
}
}