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 我想知道为什么publication
与Bookmark
的编码/解码有关,因为它被排除在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 失败:无法识别的选择器发送到实例