Codable 类不符合协议 Decodable

Posted

技术标签:

【中文标题】Codable 类不符合协议 Decodable【英文标题】:Codable class does not conform to protocol Decodable 【发布时间】:2018-07-12 02:38:30 【问题描述】:

为什么我会收到“Type 'Bookmark' does not conform to protocol 'Decodable'”错误消息?

class Bookmark: Codable 
   weak var publication: Publication?
   var indexPath: [Int]
   var locationInText = 0

   enum CodingKeys: String, CodingKey 
      case indexPath
      case locationInText
   

   init(publication: Publication?, indexPath: [Int]) 
      self.publication = publication
      self.indexPath = indexPath
   

我不想保存出版物变量,因为出版物拥有书签,但书签需要知道它属于哪个出版物。 Publication 的 decode init 会将书签引用设置为自身。

【问题讨论】:

无法在 Swift 4.0.3 (Xcode 9.2) 中重现 - 请提供minimal reproducible example? 很高兴知道为什么我的问题被否决了,这样我就可以为未来学习一些东西 不是反对者之一,但您的问题对于一个独立的示例会更有用,这样其他人就可以轻松地重现您的问题(我仍然无法重现它)。 【参考方案1】:

由于weak引用,编译器无法合成所需的init(from:)方法,需要自己编写。

class Bookmark: Codable 
    weak var publication: Publication?
    var indexPath: [Int]
    var locationInText = 0

    private enum CodingKeys: String, CodingKey 
        case indexPath
        case locationInText
    

    init(publication: Publication?, indexPath: [Int]) 
        self.publication = publication
        self.indexPath = indexPath
    

    required init(from decoder:Decoder) throws 
        let values = try decoder.container(keyedBy: CodingKeys.self)
        indexPath = try values.decode([Int].self, forKey: .indexPath)
        locationInText = try values.decode(Int.self, forKey: .locationInText)
    

【讨论】:

你的回答也是正确的,但马特是第一个。我不知道在这里做什么是正确的,但如果需要,请赐教。谢谢。 很高兴我能帮上忙。这取决于您,您接受哪个答案,但如果您发现两者都有用,无论您接受哪一个,您仍然可以对两者都投赞成票。 @Melodius 由您来选择您认为最好的答案,并为有相同问题的其他人提供最多的信息 我发现大卫的答案更有帮助,因为它有示例代码。 @DávidPásztor 我想知道为什么publicationBookmark 的编码/解码有关,因为它被排除在CodingKeys 之外?【参考方案2】:

为什么我收到“类型‘书签’不符合协议‘可解码’”错误消息

这要么是因为 Publication 不可解码(您还没有展示它是什么,所以很难判断)或者是因为 publication 上的 weak 指定。

无论哪种方式,都很容易解决:只需要实现init(from:)即可完成Decodable的实现;编译器只是告诉你这个实现不能被合成。

【讨论】:

我相信您将在 Encodable 方面遇到类似的问题,但让我们一次解决一件事。 现在可以使用了,谢谢!编码方面没有抱怨。只是好奇为什么在我没有实现 init(from:) 的情况下完全删除 CodingKeys 编译器会非常高兴? 这次发表与问题无关。 它不可解码,因为publication 在对象解码后未初始化。 weak var publication: Publication? = nil 提供一个默认值,它会变成Decodable @bshirley 如果您认为自己有更好的答案,请务必给出实际答案。【参考方案3】:

事后看来,我在尝试将 Codable 设置为包含 NSNumber 类型变量的类时收到了类似的错误。见下图:

NSNumber 更改为原始数据类型Int 解决了该问题。见下文:

我猜这可能适用于其他需要桥接到 Swift 标准库值类型的数据类型,例如 NSString、NSArray 等

【讨论】:

谢谢!就我而言,我试图使用 NSNumber。根据您的建议切换到 Int 并且成功了 @Sleeping_Giant 哈哈。不客气。一如既往的乐于助人:)【参考方案4】:

您可能会收到此消息的另一个原因是您的 CodingKeys 枚举不是详尽无遗的。如果您在数据类型中具有三个属性,那么您的 CodingKeys 枚举也需要具有三个属性/名称案例。

【讨论】:

同时检查 CodingKeys 中的拼写错误。如果只有一个不同的字符,代码将无法编译。 (这是我的情况,谢谢@mikepj) 但是指定你自己的CodingKeys 的全部意义肯定是因为你想排除一个或多个属性被编码? 我被一个字符吓跑了,我正要扯掉我的头发! 不需要在 CodingKeys 中详尽列出您的属性。如果不列出属性,则需要为其提供默认值。【参考方案5】:

仅仅因为您的 CodingKeys 枚举并不详尽,请将 publication 属性添加到枚举以实现该目的。

试试这个:

class Bookmark: Codable 
   weak var publication: Publication?
   var indexPath: [Int]
   var locationInText = 0

   // All your properties should be included
   enum CodingKeys: String, CodingKey 
      case indexPath
      case locationInText
      case publication   // this one was missing
   

您将不再需要 init 方法,因为现在可以综合实现。

【讨论】:

weak 只能应用于类和类绑定协议类型【参考方案6】:

在类似的情况下,我遇到了同样的问题,因为我的 CodingKeys 中的变量名与类变量不同。见下文

【讨论】:

【参考方案7】:

任何可编码的类都必须具有可编码的所有属性。 标准库类型(如 String、Int、Double 和 Foundation 类型(如 Date、Data 和 UR)确认可编码协议,但有些则不确认。

例如下面 注意类具有确认可编码协议的字符串的所有属性,因此没有错误:

但 UIImage 不确认可编码协议,因此会引发错误:

【讨论】:

这很有帮助。我有一个自定义类作为不可编码的属性。【参考方案8】:

简而言之,在实现 Codable 时,所有非原始数据类型(平均类类型或可能是 Objective-c 类)的属性都必须是 Codable。

   weak var publication: Publication?

在这种情况下,publication 是 type 类,因此 Publication 必须实现 Codable

【讨论】:

weak' 只能应用于类和类绑定协议类型【参考方案9】:

您可以从编码键枚举中省略一个属性,前提是它具有默认值。

来自apple docs

如果 CodingKeys 枚举中的属性在解码实例时不存在,或者某些属性不应包含在编码表示中,则忽略这些属性。 CodingKeys 中省略的属性需要一个默认值,以便其包含的类型自动符合 Decodable 或 Codable。

【讨论】:

【参考方案10】:

有点愚蠢,但以防万一它帮助别人。我收到此错误是因为我输入了 enum CodingKeys: CodingKeys 而不是 enum CodingKeys: CodingKey

【讨论】:

【参考方案11】:

我有一个类似的问题,我偶然发现了这个修复。由于我是 Swift 新手,我不确定它为什么会起作用!如果有人知道,我将不胜感激。

我改变了这个:

let id, type: Int

到这里:

let id: Int
let type: Int

【讨论】:

以上是关于Codable 类不符合协议 Decodable的主要内容,如果未能解决你的问题,请参考以下文章

符合 Codable 协议的类因 encodeWithCoder 失败:无法识别的选择器发送到实例

如果某些东西符合 Codable ,它会永远无法被编码或解码吗?

类不符合协议。为什么?

Codable和CodingKeys

如何在目标 c 数据模型类中使用 Codable 协议?

忽略 Codable 对象中的非 Codable 可选属性