vintinhum
vintinhum

Reputation: 19

Struct with protocol as property type does not conform to protocols 'Decodable' and 'Encodable'

I have a struct UISectionModel with only one property section, which has a protocol UISectionProtocol for a type, as follows:

struct UISectionModel: Codable {
    let section: UISectionProtocol
}

Here is the implementation of the UISectionProtocol protocol:

protocol UISectionProtocol: Codable {
    var identifier: String? { get }
}

As you can see, I need UISectionModel to conform to the Codable protocol, but I keep getting an error stating that it does not conform to neither Decodable or Encodable, even though the only property's type is already conforming to Codable. I suspect it has to do with the fact that this type is a protocol, but I can't figure the exact reason that is causing the error to appear or how to fix it.

Would appreciate some insight!

I tried replacing the type of section with an enum that conforms to UISectionProtocol:

struct UISectionModel: Codable {
    let section: UIDefaultSection
}

enum UIDefaultSection: UISectionProtocol {
    case imageSection(section: UIImageSection)
    case labelSection(section: UILabelSection)
    
    var identifier: String? {
        switch self {
        case .imageSection(let section): return section.identifier
        case .labelSection(let section): return section.identifier
        }
    }
}

This made the error go away, but I'm thinking that section needs to be of any type that conforms to UISectionProtocol, instead of being limited only to UIDefaultSection.

Upvotes: 0

Views: 362

Answers (2)

Md Fahim Faez Abir
Md Fahim Faez Abir

Reputation: 60

The issue you experienced is caused by protocols that don't conform to Codable. When you include a UISectionProtocol field in your UISectionModel struct, the compiler cannot guarantee that all conforming types are also Codable. To fix this problem you can make UISectionModel generic and add a type constraint to ensure the section property is also codable. Here is an updated version of your code. I think this may solve your issue.

protocol UISectionProtocol: Codable {
    var identifier: String? { get }
}
struct UISectionModel<T: UISectionProtocol>: Codable where T: Codable {
    let section: T
}

struct MySection: UISectionProtocol, Codable {
    var identifier: String?
}

Upvotes: 1

matt
matt

Reputation: 536026

I think the problem is that you probably believe that saying

protocol UISectionProtocol: Codable 

means that UISectionProtocol conforms to Codable. it doesn't. A protocol does not conform to a protocol. You probably want a generic:

struct SectionModel<T: SectionProtocol>: Codable {
    let section: T
}

protocol SectionProtocol: Codable {
    var identifier: String? { get }
}

(Note that I have stripped the illegal UI prefix off your type names; that prefix belongs to Apple alone.)

Upvotes: 2

Related Questions