Codable class does not conform to protocol Decodable

114,105

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:

enter image description here

Changing NSNumber to primitive data type Int resolved the issue. See below:

enter image description here

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.

Share:
114,105
Melodius
Author by

Melodius

Updated on July 08, 2022

Comments

  • Melodius
    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
    matt over 6 years
    I believe you will then have a parallel issue for the Encodable side, but let's fix one thing at a time.
  • Melodius
    Melodius over 6 years
    Works 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
    Melodius over 6 years
    Publication didn't have anything to do with the problem this time.
  • Melodius
    Melodius over 6 years
    Your 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
    Dávid Pásztor over 6 years
    Glad 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
    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
    Lone Ronin about 6 years
    I found David's answer more helpful since it has sample code.
  • Pavel Shorokhov
    Pavel Shorokhov over 5 years
    Also check typos in CodingKeys. If there are only one different character, code wont compile. (It was my case, thanks @mikepj)
  • Sleeping_Giant
    Sleeping_Giant over 5 years
    Thank you! In my case I was trying to use NSNumber. Switched to Int per your suggestion and bam it works
  • iOSer
    iOSer over 5 years
    @Sleeping_Giant Haha. You're Welcome. As always happy to help :)
  • Minkoo
    Minkoo over 4 years
    weak may only be applied to class and class-bound protocol types
  • Minkoo
    Minkoo over 4 years
    weak' may only be applied to class and class-bound protocol types
  • jeff-h
    jeff-h over 4 years
    But surely the whole point of specifying your own CodingKeys is because you want to exclude one or more properties from being encoded?
  • jeff-h
    jeff-h over 4 years
    @DávidPásztor I'm wondering why publication has anything to do with encoding/decoding of Bookmark, since it's excluded from the CodingKeys?
  • Hajji Daoud
    Hajji Daoud over 3 years
    I was off by a single char, I was about to rip my hair out ty!
  • DevinM
    DevinM almost 3 years
    This was very helpful. I had a custom class as a property that was not codable.
  • bshirley
    bshirley over 2 years
    You 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
    bshirley over 2 years
    It'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 become Decodable.
  • bshirley
    bshirley over 2 years
    auto-generated decoding requires all variables to be initialized afterward, instead of implementing init(from:) you can set a default value for variables not in the CodingKeys - weak var publication: Publication? = nil
  • matt
    matt over 2 years
    @bshirley If you think you have a better answer, please do give it as an actual answer.
  • Morten J
    Morten J over 2 years
    easy to make this mistake, thanks. I almost went down the custom init route, then saw your answer
  • green_knight
    green_knight about 2 years
    My 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.