90

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

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 会将书签引用设置为自身。

4

11 回答 11

62

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

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)
    }
}
于 2018-02-01T17:27:33.733 回答
46

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

要么是因为 Publication 不可解码(你没有展示它是什么,所以很难说)或者是weak因为publication.

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

于 2018-02-01T17:22:27.773 回答
31

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

在此处输入图像描述

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

在此处输入图像描述

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

于 2018-04-05T09:35:12.270 回答
31

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

于 2018-09-04T19:34:40.200 回答
19

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

于 2019-05-30T09:59:48.657 回答
12

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

在此处输入图像描述

于 2021-04-13T04:12:45.683 回答
9

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

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

但 UIImage 不确认可编码协议,所以它抛出错误: Uiimage没有可编码它显示错误

于 2020-08-21T04:29:32.687 回答
3

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

   weak var publication: Publication?

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

于 2019-01-03T08:09:47.210 回答
3

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

来自苹果文档

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

于 2019-06-03T10:43:46.170 回答
1

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

于 2020-05-26T10:23:22.220 回答
0

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

我改变了这个:

let id, type: Int

对此:

let id: Int
let type: Int
于 2018-08-16T21:15:22.697 回答