Saving array of objects in Realm with Decodable

2019-08-24 06:01发布

I've got a class which conforms to Decodable protocol (fetching data from API) and I would like to save it in the Realm database. Problem occurs when one of my properties is array (List). It says Cannot automatically synthesize Decodable because List<Item> does not conform to Decodable What is the best way to bypass this problem? Realm only supports arrays of primitive types.

here is my class:

class PartValue: Object, Decodable {
    @objc dynamic var idetifier: Int = 0
    let items = List<Item>()
}

2条回答
在下西门庆
2楼-- · 2019-08-24 06:28

Using the long awaited conditional conformances implemented in Swift 4.1, you can simply declare List to conform to Decodable in case its Element conforms to Decodable.

extension List: Decodable where List.Element: Decodable {
    public convenience init(from decoder: Decoder) throws {
        self.init()
        var container = try decoder.unkeyedContainer()
        let array = try container.decode(Array<Element>.self)
        self.append(objectsIn: array)
    }
}

To make this work for your specific case, you need to make sure that Item also conforms to Decodable.

If you also need Encodable conformance, simply extend List to support that as well.

extension List: Encodable where List.Element: Encodable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        try container.encode(contentsOf: Array(self))
    }
}
查看更多
【Aperson】
3楼-- · 2019-08-24 06:30

Dávid's solution didn't work for me completely. I had to tweak the solution instead by replacing decoder.unkeyedContainer() to decoder.singleValueContainer(), below is the solution.

extension List: Decodable where List.Element: Decodable {
    public convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.singleValueContainer()
        let array = try container.decode([Element].self)
        self.append(objectsIn: array)
    }
}
查看更多
登录 后发表回答