本文介绍了协议类型不能符合协议,因为只有具体类型才能符合协议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在应用程序中,我们有两种类型的贴纸,字符串和位图。每个贴纸包装可以同时包含两种类型。我是这样声明模型的:

// Mark: - Models

protocol Sticker: Codable {
}

public struct StickerString: Sticker,  Codable, Equatable {
    let fontName: String
    let character: String
}

public struct StickerBitmap: Sticker,  Codable, Equatable {
    let imageName: String
}

在用户选择一些贴纸并使用它们之后,我们希望将这些贴纸保存到UserDefaults中,以便向他显示"最近使用的"贴纸选项卡。我正在尝试解码保存的[Sticker]数组:

let recentStickers = try? JSONDecoder().decode([Sticker].self, from: data)

但我收到以下编译错误:

Protocol type 'Sticker' cannot conform to 'Decodable' because only concrete types can conform to protocols
我不明白为什么我声明StickerCodable,它也实现了Decodable。如有任何帮助,我们将不胜感激!

推荐答案

而不是协议使用泛型。

声明简单函数

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

T既可以是单个对象,也可以是数组。


在您的结构中删除Sticker协议。您还可以删除Equatable,因为它是在结构中合成的。

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

public struct StickerBitmap : Codable {
    let imageName: String
}

要解码其中一种贴纸类型,请对该类型进行批注

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

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

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

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

要解码StickerStringStickerBitmap类型的数组,请声明具有关联值的包装枚举

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)
        }
    }
}

然后您可以解码

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)

在表视图中,仅在枚举上switch

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
    }
}

这篇关于协议类型不能符合协议,因为只有具体类型才能符合协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 06:50