如何使用Codable的List类型? (RealmSwift)

时间:2017-08-02 06:17:03

标签: swift realm swift4

问题是List类型不符合Codable,下面的类不能插入Realm。

例如,

class Book: Codable {
    var name: String = ""
    var author: String = ""
    var tags = [String]()
}

考虑上面的类符合Codable,如果将此类存储到Realm,则需要使用List<Object>类型而不是[String]

class Book: Object, Codable {
    @objc dynamic var name: String = ""
    @objc dynamic var author: String = ""
    var tags = List<Tag>()

    required convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        author = try container.decode(String.self, forKey: .author)
        tags = try container.decode(List<Tag>.self, forKey: .tags)   // this is problem.
    }
}

class Tag: Object, Codable {
    @objc dynamic var string: String = ""

    required convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)
        string = try container.decode(String.self, forKey: .string)
    }
}

要符合Codable,应该实现Decodable协议。 (required convenience init(from decoder: Decoder) throws

但是,List类型不符合CodableDecodable),如果类具有List类型,则无法使用Codable。

如何解决此问题?

谢谢,

4 个答案:

答案 0 :(得分:9)

我们可以使用扩展名使List符合Codable:

extension List : Decodable where Element : Decodable {
    public convenience init(from decoder: Decoder) throws {
        self.init()
        var container = try decoder.unkeyedContainer()
        while !container.isAtEnd {
            let element = try container.decode(Element.self)
            self.append(element)
        }
    } }

extension List : Encodable where Element : Encodable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        for element in self {
            try element.encode(to: container.superEncoder())
        }
    } }

如果其他人需要,我还为RealmOptional提供了扩展。

  

https://gist.github.com/ansonyao/41137bb3cbbca8ef31a13b6bc96ee422

答案 1 :(得分:5)

你快到了。在初始化程序内,您可以使用解码的数组初始化列表。基本上,改变

tags = try container.decode(List<Tag>.self, forKey: .tags)   // this is problem.

let tagsArray = try container.decode([Tag].self, forKey: .tags)   
tags = List(tagsArray) // Now you are good

正如评论中所指出的,List构造函数不再像这样工作

你现在想要:

tags.append(objectsIn: tagsArray)

答案 2 :(得分:4)

接受的答案只有一个问题。 Realm指定列表应为 try: data = s.recv(buf_len) if data is not None and len(data) > 0: while True: new_data = s.recv(buf_len) if new_data is None or len(new_data) == 0: break data = data + new_data except socket.timeout: if data is not None and self.callback is not None: logger.debug(f"Received packet: {data}") incoming = data.decode('utf-8') print incoming # Process Data (常量)因此,要修改解决方案以遵循最佳实践,您只需将列表设为let,然后循环将结果附加到数组中。

let

// Change this Line in [Your Code] // to a let (Constant) var tags = List<Tag>()

然后改变

let tags = List<Tag>()

tags = try container.decode(List<Tag>.self, forKey: .tags)

答案 3 :(得分:2)

这就是您创建Realm / Swift 4 Codable模型的方法。

有关JSON响应的详细信息,模型和&amp; URLSession:Read this article

import RealmSwift

class VendorsList : Object, Decodable {
    @objc dynamic var id : Int = 0
    @objc dynamic var name : String?
    @objc dynamic var logo : String?
    // Create your Realm List.
    var kitchensList = List<VendorKitchens>()

    override class func primaryKey() -> String? {
        return "id"
    }

    private enum CodingKeys: String, CodingKey {
        case id
        case name
        case logo
        // Set JSON Object Key
        case kitchensList = "kitchens"

    }

    public required convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int.self, forKey: .id)
        self.name = try container.decode(String.self, forKey: .name)
        self.logo = try container.decode(String.self, forKey: .logo)
        // Map your JSON Array response
        let kitchens = try container.decodeIfPresent([VendorKitchens].self, forKey: .kitchensList) ?? [VendorKitchens()]
        kitchensList.append(objectsIn: kitchens)

    }

}


class VendorKitchens : Object, Decodable {
    @objc dynamic var id : Int = 0
    @objc dynamic var name : String?

    override class func primaryKey() -> String? {
        return "id"
    }

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