Reputation: 8995
Swift 4.0 iOS 11.2.x
I created a Codable stuct called products here and used this method to save it to file.
func saveImage() {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let file2ShareURL = documentsDirectoryURL.appendingPathComponent("config.n2kHunt")
var json: Any?
let encodedData = try? JSONEncoder().encode(products)
if let data = encodedData {
json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let json = json {
do {
try String(describing: json).write(to: file2ShareURL, atomically: true, encoding: .utf8)
} catch {
print("unable to write")
}
}
}
}
It works and assuming I enter two records I get this on file. [which isn't json, but whatever].
(
{
identity = "blah-1";
major = 245;
minor = 654;
url = "https://web1";
uuid = f54321;
},
{
identity = "blah-2";
major = 543;
minor = 654;
url = "https://web2";
uuid = f6789;
}
)
I airdrop the file to a second iOS device, where I try and decode it with this procedure in appDelegate.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
do {
let string2D = try? String(contentsOf: url)
let jsonData = try? JSONSerialization.data(withJSONObject: string2D)
do {
products = try JSONDecoder().decode([BeaconDB].self, from: jsonData!)
} catch let jsonErr {
print("unable to read \(jsonErr)")
}
} catch {
print("application error")
}
}
And I get a mother crash, with this error message...
2018-03-06 21:20:29.248774+0100 blah[2014:740956] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write'
What am I doing wrong; how can I write json to a file such that I can read it back!! Ironically I made this code work with a plist a few days back, I hate json.
Upvotes: 0
Views: 2026
Reputation: 285290
Why do you encode the struct to JSON, then deserialize the JSON to Swift Array and save the collection type string representation(!) to disk? The other way round cannot work and that causes the error.
It's much easier:
func saveImage() {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let file2ShareURL = documentsDirectoryURL.appendingPathComponent("config.n2kHunt")
do {
let encodedData = try JSONEncoder().encode(products)
try encodedData.write(to: file2ShareURL)
} catch {
print("unable to write", error)
}
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
do {
let jsonData = try Data(contentsOf: url)
products = try JSONDecoder().decode([BeaconDB].self, from: jsonData)
} catch {
print("unable to read", error)
}
}
Notes:
catch
clause, print at least the actual error
.try?
in a do - catch
block. Write try
without question mark to do catch the errors.Upvotes: 3