问题
Why am I getting a "Type 'Bookmark' does not conform to protocol 'Decodable'" error message?
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
}
}
I do not wish to save the publication var since the Publication owns the Bookmark but the bookmark needs to know which Publication it belongs to. The decode init of Publication will set the bookmark reference to itself.
回答1:
Why am I getting a "Type 'Bookmark' does not conform to protocol 'Decodable'" error message
It's either because Publication isn't Decodable (you have not shown what it is, so it's hard to tell) or because of the weak
designation on publication
.
Either way, it's easy to fix: you just need to implement init(from:)
to complete the implementation of Decodable; the compiler is simply telling you that this implementation cannot be synthesized.
回答2:
The compiler cannot synthesise the required init(from:)
method due to the weak
reference, so you need to write it yourself.
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)
}
}
回答3:
On the hindsight, I received a similar error when trying to set Codable
to my class which consisted of NSNumber type variables. See image below:
Changing NSNumber
to primitive data type Int
resolved the issue. See below:
I'm guessing this might be true for other datatypes that require bridging to Swift Standard Library Value Types such as NSString, NSArray and so on
回答4:
Another reason you could get this message is if your CodingKeys enum isn't exhaustive. If you have three properties in the data type, then your CodingKeys enum needs to have three property/name cases as well.
回答5:
Simply because your CodingKeys enum is not exhaustive, add publication
property to the enum to achieve that.
try this:
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
}
}
You wont need the init method anymore as the implementation now can be synthesized.
回答6:
In-short, while implementing Codable, all properties which are non-primitive data type (mean class type or may it can be objective-c class) must be Codable.
weak var publication: Publication?
in this case publication is of type class so Publication must have implemented Codable
回答7:
You can omit a property from coding keys enum, only if it has a default value.
From 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.
回答8:
I had a similar issue which I stumbled upon this fix to. As I am new to Swift, I am unsure as to why it works! If anyone knows I would appreciate the knowledge.
I changed this:
let id, type: Int
to this:
let id: Int
let type: Int
回答9:
I solve this by changing my struct name to current swift file that I want the struct. For example, I want to put this into BookmarkModel.swift
, so instead type this:
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
}
}
Change to this:
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
}
}
来源:https://stackoverflow.com/questions/48568373/codable-class-does-not-conform-to-protocol-decodable