RealmSwift LinkingObjects and Decodable

2019-08-20 01:41发布

问题:

I have a Realm model class that I need to be Decodable so I can serialize it from JSON and save it to database. Every PortfolioItem is associated with one Product and at some point I need to get to PortfolioItem from Product via inverse relationship. That's why I have LinkingObjects property. The problem is when I try to conform to Decodable protocol. The compiler is giving me an error Cannot automatically synthesize 'Decodable' because 'LinkingObjects<PortfolioItem>' does not conform to 'Decodable' . How to deal with this? I found very little about LinkingObjects and Decodable online and I have no idea how to approach this.

class PortfolioItem: Object {

    @objc dynamic var id: String = ""
    @objc dynamic var productId: String = ""

    @objc dynamic public var product: Product?

    convenience init(id: String, productId: String) {
        self.init()
        self.id = id
    }

}

final class Product: Object, Decodable {

    @objc dynamic var id: String = ""
    @objc dynamic var name: String = ""

    private let portfolioItems = LinkingObjects(fromType: PortfolioItem.self, property: "product")

    public var portfolioItem: PortfolioItem? {
        return portfolioItems.first
    }

    convenience init(id: String, name: String) {
        self.init()
        self.id = id
    }
}

Big thanks to Chris Shaw for helping me figure this out. I wrote a more in-depth article how to setup Decodable and LinkingObjects, look HERE.

回答1:

Well unless I'm missing something then the LinkingObjects properties does not need to be included in the decoding.

My assumption here is that you're receiving JSON from some online source, where the JSON for a Product consists of { id: "", name: "" }. As long as you're creating the PortfolioItem correctly with associated Product, then the resulting LinkingObjects property is the result of a dynamic query within Realm (and will thus work without any JSON source).

I'm not in a position to test compile an answer today, but you should be able to use CodingKeys to simply exclude that property, i.e. by adding this to Product:-

private enum CodingKeys: String, CodingKey {
    case id
    case name
}

Also, unrelated, but note that your convenience init function are not initialising all properties that you're passing in.