Codable class 不符合 Decodable 协议

Codable class does not conform to protocol Decodable

为什么我会收到 "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 的解码初始化会将书签引用设置为自身。

Why am I getting a "Type 'Bookmark' does not conform to protocol 'Decodable'" error message

这要么是因为 Publication 不是 Decodable(您没有显示它是什么,所以很难说),要么是因为 publication 上的 weak 指定。

无论哪种方式,修复起来都很容易:你只需要实现init(from:)即可完成Decodable的实现;编译器只是告诉你这个实现无法合成。

由于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)
    }
}

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

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

我猜这对于需要桥接到 Swift 标准库值类型(例如 NSString、NSArray 等)的其他数据类型可能是正确的

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

我改变了这个:

let id, type: Int

对此:

let id: Int
let type: Int

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

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

   weak var publication: Publication?

在这种情况下,发布的类型为 class,因此发布必须已实现 Codable

仅仅因为您的 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 方法,因为现在可以合成实现。

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

来自apple docs

Omit properties from the CodingKeys enumeration if they won't be present when decoding instances, or if certain properties shouldn't be included in an encoded representation. A property omitted from CodingKeys needs a default value in order for its containing type to receive automatic conformance to Decodable or Codable.

有点愚蠢,但以防万一它对其他人有帮助。我得到这个错误是因为我把 enum CodingKeys: CodingKeys 而不是 enum CodingKeys: CodingKey.

要成为可编码的任何 class 必须全部 属性 可编码。 String、Int、Double 等标准库类型和 Date、Data 和 UR 等基础类型确认可编码协议,但有些不确认。

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

但是 UIImage 不确认可编码协议,因此它抛出错误:

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