问题
In SwiftUI beta 5, Apple introduced the @Published annotation. This annotation is currently blocking this class from conforming to the Codable protocols.
How can I conform to these protocols so I can encode and decode this class to JSON? You can ignore the image property for now.
class Meal: ObservableObject, Identifiable, Codable {
enum CodingKeys: String, CodingKey {
case id
case name
case ingredients
case numberOfPeople
}
var id = Globals.generateRandomId()
@Published var name: String = "" { didSet { isInputValid() } }
@Published var image = Image("addImage")
@Published var ingredients: [Ingredient] = [] { didSet { isInputValid() } }
@Published var numberOfPeople: Int = 2
@Published var validInput = false
func isInputValid() {
if name != "" && ingredients.count > 0 {
validInput = true
}
}
}
回答1:
Add the init()
and encode()
methods to your class:
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decode(Int.self, forKey: .id)
name = try values.decode(String.self, forKey: .name)
ingredients = try values.decode([Ingredient].self, forKey: .ingredients)
numberOfPeople = try values.decode(Int.self, forKey: .numberOfPeople)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(ingredients, forKey: .ingredients)
try container.encode(numberOfPeople, forKey: .numberOfPeople)
}
回答2:
After much hacking around, I managed to add Codable directly to @Published
Just add the code below in a file and your @Published variables will be automatically Codable (provided they are based on a Codable type)
more info here https://blog.hobbyistsoftware.com/2020/01/adding-codeable-to-published/
code here:
import Foundation
import SwiftUI
extension Published:Decodable where Value:Decodable {
public init(from decoder: Decoder) throws {
let decoded = try Value(from:decoder)
self = Published(initialValue:decoded)
}
}
extension Published:Encodable where Value:Decodable {
public func encode(to encoder: Encoder) throws {
let mirror = Mirror(reflecting: self)
if let valueChild = mirror.children.first(where: { $0.label == "value"
}) {
if let value = valueChild.value as? Encodable {
do {
try value.encode(to: encoder)
return
} catch let error {
assertionFailure("Failed encoding: \(self) - \(error)")
}
}
else {
assertionFailure("Decodable Value not decodable. Odd \(self)")
}
}
else {
assertionFailure("Mirror Mirror on the wall - why no value y'all : \(self)")
}
}
}
来源:https://stackoverflow.com/questions/57444059/how-to-conform-an-observableobject-to-the-codable-protocols