Christian
Christian

Reputation: 382

Swift 4 Codable in protocol with enum property

I have this protocol,

protocol PaginableItem {
   var resultType: ResultType { get set }
}

with a single property of an enum type,

enum ResultType: String, Codable {
   case photo = "PHOTO"
   case baseItem = "BASEITEM"
   case new = "NEW"
}

I also have 3 different structs and classes with conforms to PaginableItem and a class with some PaginableItems,

final class TimelineModel: Codable {
   let stream: String
   let participants: String
   let header1: PaginableList
   let header2: PaginableList
   let items: PaginableList
}

final class PaginableList: Codable {
   let data: [PaginableItem]
   let pagination: Pagination
}

I'm trying to cache TimelineModel using Swift 4 Codable, but I'm not sure the best way to do that. Xcode is complaining about PaginableItem not conforming to Codable.

It is mandatory to implement init(from decoder: Decoder) throws and encode(to encoder: Encoder) throws in ResultType?

Must PaginableItem implement Codable also?

Upvotes: 2

Views: 2305

Answers (2)

mj_jimenez
mj_jimenez

Reputation: 443

PaginableItem can't conform to Codable is because Swift protocols can't conform to themselves.

Source:

Protocol doesn't conform to itself?

Encode/Decode Array of Types conforming to protocol with JSONEncoder

Following the second link above, if you want to encode/decode a PaginableItem you have to type erase them in an AnyPaginableItem class/struct and make that conform to Encodable/Decodable. I've done it like so:

protocol PaginableItem {
    var resultType: ResultType { get set }
}

class AnyPaginableItem: Codable {
    var resultType: ResultType

    init(resultType: ResultType) {
        self.resultType = resultType
    }
}

enum ResultType: String, Codable {
    case photo = "PHOTO"
    case baseItem = "BASEITEM"
    case new = "NEW"
}

struct ContainsPaginableItem: Codable {
    let paginableItem: AnyPaginableItem
}

let paginableItem = AnyPaginableItem(resultType: .photo)
let itemToEncode = ContainsPaginableItem(paginableItem: paginableItem)

let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(itemToEncode)
let jsonString = String(data: jsonData, encoding: .utf8)

This example only encodes the properties that can be declared in PaginableItem, which I assume is all you need.

If you need to encode ALL of the properties of the type conforming to PaginableItem there's a longer solution in the second link above that you can adopt.

Upvotes: 4

FullMetalFist
FullMetalFist

Reputation: 208

Must PaginableItem implement Codable also?

Absolutely! By making sure PaginableItem conforms to Codable, you maintain overall conformance to Codable for PaginableList.

I notice you had ResultType conform to Codable. However what happens if PaginableItem adds another object which does not - could be the danger.

Upvotes: 0

Related Questions