Roi*_*lia 17 protocols ios swift codable decodable
在应用程序中,我们有两种类型的贴纸,字符串和位图。每个贴纸包可以包含这两种类型。这就是我声明模型的方式:
// 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
}
Run Code Online (Sandbox Code Playgroud)
在用户选择一些贴纸并使用它们后,我们希望将这些贴纸保存到其中,UserDefaults以便我们可以向他显示“最近使用过的”贴纸选项卡。我正在尝试解码保存的[Sticker]数组:
let recentStickers = try? JSONDecoder().decode([Sticker].self, from: data)
Run Code Online (Sandbox Code Playgroud)
但我收到以下编译错误:
Protocol type 'Sticker' cannot conform to 'Decodable' because only concrete types can conform to protocols
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我声明Stickeras Codablewhich 也实现了Decodable. 任何帮助将不胜感激!
vad*_*ian 12
而不是协议使用泛型。
声明一个简单的函数
func decodeStickers<T : Decodable>(from data : Data) throws -> T
{
return try JSONDecoder().decode(T.self, from: data)
}
Run Code Online (Sandbox Code Playgroud)
T 可以是单个对象也可以是数组。
在您的结构中删除Sticker协议。您也可以删除,Equatable因为它正在结构中合成。
public struct StickerString : Codable {
let fontName: String
let character: String
}
public struct StickerBitmap : Codable {
let imageName: String
}
Run Code Online (Sandbox Code Playgroud)
要解码其中一种贴纸类型,请对该类型进行注释
let imageStickers = """
[{"imageName":"Foo"},{"imageName":"Bar"}]
"""
let stickerData = Data(imageStickers.utf8)
let recentStickers : [StickerBitmap] = try! decodeStickers(from: stickerData)
print(recentStickers.first?.imageName)
Run Code Online (Sandbox Code Playgroud)
和
let stringSticker = """
{"fontName":"Times","character":""}
"""
let stickerData = Data(stringSticker.utf8)
let sticker : StickerString = try! decodeStickers(from: stickerData)
print(sticker.character)
Run Code Online (Sandbox Code Playgroud)
要解码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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后就可以解码了
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)
Run Code Online (Sandbox Code Playgroud)
在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
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31182 次 |
| 最近记录: |