Reputation: 86
I'm just starting out on learning SwiftUI. Where do I go wrong? I'm trying to add Codable conformance in my class (ManyItems). This so I eventually can save an array to disk using JSON. Two errors:
1) In both the "required init(...) "id = try..." and the encode func: "try container.encode..." result in "'id' is unavailable in Swift: 'id' is not available in Swift; use 'Any'"
2) In both the required init(...) and func encode: "Use of unresolved identifier 'one'." I assumed the identifier in the struct would be carried forward into the class?
struct Item: Identifiable {
var id = UUID()
var one: String
}
class ManyItems: ObservableObject, Codable {
@Published var manyitems = [Item]()
enum CodingKeys: CodingKey {
case id
case one
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
one = try container.decode(String.self, forKey: .one)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(one, forKey: .one)
}
}
Upvotes: 2
Views: 1948
Reputation: 86
I've found a solution but had to take a slightly different route. Hopefully this could help someone else who needs to use a Collection conforming to Codable and ObservableObject for saving to the Apps documentDirectory.
I conformed the struct 'Item' to Codable (i.e not the class 'ManyItem'). I added code for JSON encoding and saving of the Collection to the Apps documentDirectory. This happens automatic when a property value changes. The class is initiated through either a read/decoding of the JSON file from the Apps document directory or as a new blank instance if the JSON file is not available yet.
struct Item: Identifiable, Codable {
var id = UUID()
var one: String
}
class ManyItems: ObservableObject {
@Published var manyitems: [Item] {
didSet {
// Saves the array 'items' to disc
do {
// find the documentDirectory and create an URL for the JSON
file
let filename = getDocumentsDirectory().appendingPathComponent("manyitems.json")
let data = try JSONEncoder().encode(self.manyitems)
try data.write(to: filename, options: [.atomicWrite])
} catch {
print("Unable to save data.")
}
}
}
init() {
// replaces a call to 'getDocumentsDirectory()' methode as it created an initialisation error.
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
// Add the first [0] path to the filename and create 'filename'
let filename = paths[0].appendingPathComponent("manyitems.json")
//print(filename)
do {
// Try to read the file (if it exist) and load the data into the array 'manyitem'
let data = try Data(contentsOf: filename)
manyitems = try JSONDecoder().decode([Item].self, from: data)
// Yes all good then exit
return
} catch {
// Something whent wrong. Initialize by creating an empty array 'manyitems'
self.manyitems = []
print("Unable to load saved data.")
}
}
// retreives the App's first DocumentDirectory
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
}
Upvotes: 0
Reputation: 24341
Your Codable
models should be,
struct Item: Codable, Identifiable {
var id = UUID()
var one: String
}
class ManyItems: Codable, ObservableObject {
@Published var manyitems = [Item]()
}
As evident from your code, you're not handling any specific parsing cases. So, there is no need to explicitly implement init(from:)
and encode(to:)
methods.
Upvotes: -1