Codable class does not conform to protocol Decodable
Solution 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.
Solution 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)
}
}
Solution 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
Solution 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.
Solution 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.
Melodius
Updated on July 08, 2022Comments
-
Melodius almost 2 years
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.
-
matt over 6 yearsI believe you will then have a parallel issue for the Encodable side, but let's fix one thing at a time.
-
Melodius over 6 yearsWorks now thanks! Encodable side did not complain. Just curious as to why the compiler is perfectly happy if I remove CodingKeys altogether when I haven't implemented init(from:)?
-
Melodius over 6 yearsPublication didn't have anything to do with the problem this time.
-
Melodius over 6 yearsYour answer was correct too but matt was first. I don't know what the proper thing to do here is, but enlighten me if needed. Thanx.
-
Dávid Pásztor over 6 yearsGlad I could help. It's up to you, which answer you accept, but if you found both useful, you can still upvote both regardless of which one do you accept.
-
ColdLogic about 6 years@Melodius up to you to choose which answer you think is best and would provide the most information to other people with the same question
-
Lone Ronin about 6 yearsI found David's answer more helpful since it has sample code.
-
Pavel Shorokhov over 5 yearsAlso check typos in CodingKeys. If there are only one different character, code wont compile. (It was my case, thanks @mikepj)
-
Sleeping_Giant over 5 yearsThank you! In my case I was trying to use NSNumber. Switched to Int per your suggestion and bam it works
-
iOSer over 5 years@Sleeping_Giant Haha. You're Welcome. As always happy to help :)
-
Minkoo over 4 yearsweak may only be applied to class and class-bound protocol types
-
Minkoo over 4 yearsweak' may only be applied to class and class-bound protocol types
-
jeff-h over 4 yearsBut surely the whole point of specifying your own
CodingKeys
is because you want to exclude one or more properties from being encoded? -
jeff-h over 4 years@DávidPásztor I'm wondering why
publication
has anything to do with encoding/decoding ofBookmark
, since it's excluded from theCodingKeys
? -
Hajji Daoud over 3 yearsI was off by a single char, I was about to rip my hair out ty!
-
DevinM almost 3 yearsThis was very helpful. I had a custom class as a property that was not codable.
-
bshirley over 2 yearsYou do NOT need to exhaustively list your properties in the CodingKeys. If you do not list a property, you need to provide a default value for it.
-
bshirley over 2 yearsIt's not decodable because
publication
isn't initialized after the object is decoded.weak var publication: Publication? = nil
Provide a default value and it be becomeDecodable
. -
bshirley over 2 yearsauto-generated decoding requires all variables to be initialized afterward, instead of implementing
init(from:)
you can set a default value for variables not in theCodingKeys
-weak var publication: Publication? = nil
-
matt over 2 years@bshirley If you think you have a better answer, please do give it as an actual answer.
-
Morten J over 2 yearseasy to make this mistake, thanks. I almost went down the custom init route, then saw your answer
-
green_knight about 2 yearsMy problem was working with SwiftUI and having one variable inside my class marked as @Publishable. Everything conforms to Codable, but the compiler still choked. Conformed manually, everything works fine.