不要使用协议,而是使用泛型。
声明一个简单的函数。
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)
为了解码一个由
StickerString
和
StickerBitmap
类型组成的数组,需要声明一个带有关联值的包装枚举。
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
return cell
case .image(let imageSticker):
let cell = tableView.dequeueReusableCell(withCellIdentifier: "ImageStickerCell", for: indexPath) as! ImageStickerCell
return cell
}
}
decode
的第一个参数必须是具体类型。解决方案是使用一个受限于Codable
的泛型类型。 - vadianStickerString
和StickerBitmap
。 - vadianSticker
中添加了associatedtype
,并在StickerString
和StickerBitmap
中使用typealias
分别指定它们自己的类型,但是仍然出现相同的错误。我是否能够声明一个[Sticker]
数组,或者只能使用其中一种具体类型? - Roi Mulia