Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conform an ObservableObject to the Codable protocols?

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
        }
    }
}

like image 245
Tristan Diependael Avatar asked Aug 10 '19 16:08

Tristan Diependael


People also ask

Can a protocol be Codable?

Codable Protocol is the composition of two protocols known as 'Encodable' & 'Decodable'.

Can a class be Codable?

Remember, Swift's String , Int , and Bool are all Codable ! Earlier I wrote that your structs, enums, and classes can conform to Codable . Swift can generate the code needed to extract data to populate a struct's properties from JSON data as long as all properties conform to Codable .

What is the use of Codable protocol in Swift?

Codable is the combined protocol of Swift's Decodable and Encodable protocols. Together they provide standard methods of decoding data for custom types and encoding data to be saved or transferred.

What is a Codable?

Codable is a type alias for the Encodable and Decodable protocols. When you use Codable as a type or a generic constraint, it matches any type that conforms to both protocols.


1 Answers

A more efficient variant without Mirror

Published+Value.swift

private class PublishedWrapper<T> {
    @Published private(set) var value: T

    init(_ value: Published<T>) {
        _value = value
    }
}

extension Published {
    var unofficialValue: Value {
        PublishedWrapper(self).value
    }
}

Published+Codable.swift

extension Published: Decodable where Value: Decodable {
    public init(from decoder: Decoder) throws {
        self.init(wrappedValue: try .init(from: decoder))
    }
}

extension Published: Encodable where Value: Encodable {
    public func encode(to encoder: Encoder) throws {
        try unofficialValue.encode(to: encoder)
    }
}
like image 68
Steven Avatar answered Sep 28 '22 02:09

Steven