【问题标题】:List is not conforming to Encodable列表不符合 Encodable
【发布时间】:2018-02-05 09:12:13
【问题描述】:

所以,我正在使用领域,并且两个模型之间存在以下关系:A unit has many tests

 // Unit model
 class Unit: Object, Decodable {
     @objc dynamic var id: String = ""
     ...
     let tests = List<Test>()

     enum CodingKeys: String, CodingKey {
          case id
          ...
          //case tests = "complete_control_tests"
     }

     convenience required init(from decoder: Decoder) throws {
          self.init()
          let container = try decoder.container(keyedBy: CodingKeys.self)
          id = try container.decode(String.self, forKey: .id)
          ...
          if let arr = try container.decodeIfPresent(Array<Test>.self, forKey: .tests) {
                tests.append(objectsIn: arr)
          } else {
                self.tests.append(objectsIn: [])
          }
     }
 }
 // Test model
 class Test: Object, Decodable {
     @objc dynamic var id: String = ""
     @objc dynamic var room_control_id: String = ""

     enum CodingKeys: String, CodingKey {
          case id
          case room_control_id = "room_control_id"

     }
 }

tests 属性被注释时,我可以正确解析该模型的 json 输出。但是当我取消注释时,我有以下错误:

Swift.Encodable:12:17: Protocol requires function 'encode(to:)' with type 'Encodable'
Models/Unit.swift:27:6: Cannot automatically synthesize 'Encodable' because 'List<Test>' does not conform to 'Encodable'

有没有办法让 Codable 和 Realm 玩得更好?

【问题讨论】:

    标签: swift realm swift4 codable


    【解决方案1】:

    您的代码存在几个问题。首先,如果您只想实现init(from:) 方法,而不是encode 方法,请声明符合Decodable 而不是Codable。其次,您需要在创建自己的init(from:) 方法时实现CodingKeys,并且还需要从便利初始化程序中调用您的类的指定初始化程序。

    在初始化器中也不需要else 子句,因为tests 已经被初始化为一个空的List 并且向它附加一个空数组是没有意义的。

    class Unit: Object, Decodable {
        @objc dynamic var id: String = ""
        let tests = List<Test>()
    
        private enum CodingKeys: String, CodingKey {
            case id, tests
        }
    
        convenience required init(from decoder: Decoder) throws {
            self.init()
            let container = try decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(String.self, forKey: .id)
            if let arr = try container.decodeIfPresent(Array<Test>.self, forKey: .tests) {
                tests.append(objectsIn: arr)
            }
        }
    }
    

    【讨论】:

    • 我已经用我现有的代码更新了我的初始帖子,其中已经包含您评论中所述的所有要点。尽管如此,鉴于错误,我的项目无法编译。
    • @SahbiBelgacem 您仍在使用Codable 而不是Decodable,因此出现错误。如果您实际使用的是Decodable,则不会出现引用Encodable 一致性的错误
    • 抱歉,我已经更新了我的代码。我写的不是Decodable,而是Codable
    • @SahbiBelgacem 您问题中的代码,但错误仍然不一致。如果您只声明符合Decodable,则不会收到关于Encodable 的错误。此外,我的答案中的代码编译时没有任何错误,我在发布之前已经对其进行了测试,所以如果你使用相同的代码,你不会得到任何编译器错误。
    • 我知道!这很奇怪。我已经清理了缓存,现在它正在工作。 ¯_(ツ)_/¯
    【解决方案2】:

    第一条错误消息明确指出,如果您实现自定义 init 方法 (decode),您还必须实现 encode(to:) (encode) 以符合协议。

    如果你只是解码对象而不需要编码它只采用Decodable. 否则执行encode(to:)

    要解决第二个错误,请显式声明CodingKeys

    【讨论】:

    • 即使我使用Decodable而不是Codable,我也会遇到同样的错误!
    • 发生第二个错误是因为编码密钥tests 期望解码List&lt;Test&gt;,但您正在解码Array&lt;Test&gt;。为List&lt;Test&gt; 声明一个具有不同名称的属性或显式声明编码键。
    • 因为我不能这样做:tests = try container.decode(List&lt;Test&gt;.self, forKey: .tests)。这就是为什么我先使用一个数组,然后将它附加到测试的属性中。
    • 一种解决方案是另外声明 let testArray : Array&lt;Test&gt; 为 dummy 并解码 if let arr = try container.decodeIfPresent(Array&lt;Test&gt;.self, forKey: .testArray) 或者 - 如前所述 - 显式声明编码密钥以将密钥与属性名称分开。
    • 但是领域的文档明确声明使用list 将对象链接在一起!。另外,它似乎适用于其他用户,但不适用于我:(。GH: Class does not conform "Encodable" while using List<String> in swift 4.0
    【解决方案3】:

    我找到了它不起作用的原因。这是 Xcode 的缓存。我已经删除了 Xcode Derived 数据文件夹的内容,现在它正在正确编译和解析 json。

    对不起,伙计们!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多