This was my solution to that:
extension FileManager {
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func decode<T: Codable>(_ fromFile: String) -> T? {
let url = getDocumentsDirectory().appendingPathComponent(fromFile)
let decoder = JSONDecoder()
do {
let savedData = try Data(contentsOf: url)
do {
let decodedData = try decoder.decode(T.self, from: savedData)
return decodedData
} catch {
print(error.localizedDescription)
print("Decoding Failed!")
}
} catch {
print(error.localizedDescription)
print("Read Failed!")
}
return nil
}
func encode<T: Codable>(_ data: T, toFile fileName: String) {
let encoder = JSONEncoder()
do {
let encoded = try encoder.encode(data)
let url = getDocumentsDirectory().appendingPathComponent(fileName)
do {
try encoded.write(to: url)
} catch {
print(error.localizedDescription)
print("Write Failed!")
}
} catch {
print(error.localizedDescription)
print("Encoding Failed!")
}
}
}
I found this to be difficult to figure out as well. I used Paul's Bundle-Decodable that he had given us previously as template:
extension Bundle {
func decode<T: Codable>(_ file: String) -> T {
guard let fileUrl = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to find \(file) in bundle.")
}
guard let data = try? Data(contentsOf: fileUrl) else {
fatalError("Failed to load \(file) from bundle.")
}
guard let decodedData = try? JSONDecoder().decode(T.self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}
return decodedData
}
}
I took it one step at a time and figured out the code for performing the encode and decode without using generics and without using an extension. Once I got that working, I implemented the generics. Once I got that working I implemented the extension. This is not a totally complete solution if you're decoding dates but that wasn't part of this particular challenge either. I also don't think you need to nest one do try catch inside the other but it was helpful to me to get the specific print messages that were more helpful to me than the error.localizedDescription.
That's another thing I did when I was trying to figure it out. I had print statements all over the place to see what was working and what wasn't working.