I've been trying to figure out the best solution for data persistence for an app I'm working on and I decided a locally stored JSON file will be the best balance of simplicity and functionality.
What I need to save is an array of custom structs, and I can write it just fine using the code below, but I can't decode it back, I'm getting this error:
Cannot invoke 'decode' with an argument list of type '([Idea], from: Data)'
Any idea what's causing this? Is the ideas array itself supposed to be Codable? Encoding it shouldn't have worked then right? Am I doing something else wrong?
Any suggestions would be appreciated.
var ideas = [Idea]()
--
struct Idea: Codable {
var title: String
var description: String?
var date: String
var completed: Bool
}
--
func writeIdeasToJSON(){
let pathDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
try? FileManager().createDirectory(at: pathDirectory, withIntermediateDirectories: true)
let filePath = pathDirectory.appendingPathComponent("data.json")
let json = try? JSONEncoder().encode(ideas)
do {
try json!.write(to: filePath)
} catch {
print("Failed to write JSON data: \(error.localizedDescription)")
}
}
--
func readIdeasFromJSON(){
do {
let path = Bundle.main.path(forResource: "data", ofType: "json")
let jsonData = try Data(contentsOf: URL(fileURLWithPath: path!))
do {
let readIdeas = try JSONDecoder().decode(ideas.self, from: jsonData)
print(readIdeas)
} catch let error{
print(error.localizedDescription)
}
} catch let error {
print(error.localizedDescription)
}
}
You have two issues. First is the compiler error from:
let readIdeas = try JSONDecoder().decode(ideas.self, from: jsonData)
That needs to be :
let readIdeas = try JSONDecoder().decode([Idea].self, from: jsonData)
With that fixed you get a runtime error because you wrote the file to the Documents folder but you attempt to read it from the app's resource bundle.
Update your loading code to use the same path used to save the file:
func readIdeasFromJSON(){
do {
let pathDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let filePath = pathDirectory.appendingPathComponent("data.json")
let jsonData = try Data(contentsOf: filePath)
let readIdeas = try JSONDecoder().decode([Idea].self, from: jsonData)
print(readIdeas)
} catch {
print(error)
}
}