Protocol type cannot conform to protocol because only concrete types can conform to protocols

Rather than protocols use generics.

Declare a simple function

func decodeStickers<T : Decodable>(from data : Data) throws -> T
{
    return try JSONDecoder().decode(T.self, from: data)
}

T can be a single object as well as an array.


In your structs drop the Sticker protocol. You can also delete Equatable because it's getting synthesized in structs.

public struct StickerString : Codable {
    let fontName: String
    let character: String
}

public struct StickerBitmap : Codable {
    let imageName: String
}

To decode one of the sticker types annotate the type

let imageStickers = """
[{"imageName":"Foo"},{"imageName":"Bar"}]
"""    
let stickerData = Data(imageStickers.utf8)

let recentStickers : [StickerBitmap] = try! decodeStickers(from: stickerData)
print(recentStickers.first?.imageName)

and

let stringSticker = """
{"fontName":"Times","character":""}
"""    
let stickerData = Data(stringSticker.utf8)

let sticker : StickerString = try! decodeStickers(from: stickerData)
print(sticker.character)

To decode an array of StickerString and StickerBitmap types declare a wrapper enum with associated values

enum Sticker: Codable {

    case string(StickerString)
    case image(StickerBitmap)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            let stringData = try container.decode(StickerString.self)
            self = .string(stringData)
        } catch DecodingError.keyNotFound {
            let imageData = try container.decode(StickerBitmap.self)
            self = .image(imageData)
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
            case .string(let string) : try container.encode(string)
            case .image(let image) : try container.encode(image)
        }
    }
}

Then you can decode

let stickers = """
[{"imageName":"Foo"},{"imageName":"Bar"}, {"fontName":"Times","character":""}]
"""

let stickerData = Data(stickers.utf8)
let recentStickers = try! JSONDecoder().decode([Sticker].self, from: stickerData)
print(recentStickers)

In a table view just switch on the enum

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let sticker = stickers[indexPath.row]
    switch sticker {
    case .string(let stringSticker): 
        let cell = tableView.dequeueReusableCell(withCellIdentifier: "StringStickerCell", for: indexPath) as! StringStickerCell
        // update UI
        return cell
    case .image(let imageSticker): 
        let cell = tableView.dequeueReusableCell(withCellIdentifier: "ImageStickerCell", for: indexPath) as! ImageStickerCell
        // update UI
        return cell
    }
}