Codable类不符合协议Decodable

时间:2018-02-01 17:19:32

标签: swift swift4 codable 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
   }
}

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

12 个答案:

答案 0 :(得分:29)

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

答案 1 :(得分:20)

  

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

这可能是因为出版物不是可解码的(你没有表明它是什么,所以很难说)或者因为weak上的publication指定。

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

答案 2 :(得分:15)

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

enter image description here

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

enter image description here

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

答案 3 :(得分:10)

您可能收到此消息的另一个原因是,如果您的CodingKeys枚举不完整。如果数据类型具有三个属性,则您的CodingKeys枚举也需要具有三个属性/名称大小写。

答案 4 :(得分:6)

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

enter image description here

答案 5 :(得分:1)

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

   weak var publication: Publication?

在这种情况下,发布属于类别类,因此发布必须已实现Codable

答案 6 :(得分:1)

有点愚蠢,但以防万一。之所以出现此错误,是因为我放了enum CodingKeys: CodingKeys而不是enum CodingKeys: CodingKey

答案 7 :(得分:0)

我遇到了类似的问题,偶然发现了此修复程序。因为我是Swift的新手,所以我不确定它为什么起作用!如果有人知道,我将不胜感激。

我更改了此内容

let id, type: Int

对此:

let id: Int
let type: Int

答案 8 :(得分:0)

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

答案 9 :(得分:0)

只有在具有默认值的情况下,才可以从编码键枚举中省略属性。

来自apple docs

  

如果在解码实例时不存在这些属性,或者如果某些属性不应包含在编码表示形式中,请从CodingKeys枚举中省略属性。从CodingKeys省略的属性需要一个默认值,以便其包含类型能够自动接收与Decodable或Codable相符的信息。

答案 10 :(得分:0)

我通过将结构名称更改为我想要的结构的当前swift文件来解决此问题。例如,我要将其放入BookmarkModel.swift中,因此键入:

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
   }
}

更改为此:

class BookmarkModel: 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
       }
    }

答案 11 :(得分:-1)

任何应编码的对象类都必须采用NSCoding协议并实现其方法。来自apple

类的所有属性都应具有可编码协议,以使类可编码。单击数据类型并搜索将显示的可编码(如果有)。 enter image description here

字符串具有可编码协议,因此没有错误: String has codable protocol so class has no error UIImage没有可编码协议,因此显示错误: Uiimage don't have codable it shows error