协议类型不能符合协议,因为只有具体类型才能符合协议
Protocol type cannot conform to protocol because only concrete types can conform to protocols
在应用程序中,我们有两种类型的贴纸,字符串和位图。每个贴纸包都可以包含两种类型。这就是我声明模型的方式:
// 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
中,以便我们可以向他显示 "Recently Used" 贴纸选项卡。我正在尝试解码保存的 [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
我不明白为什么我将 Sticker
声明为 Codable
而它也实现了 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)
要解码 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)
在 table 视图中 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
}
}
这里发生的事情是不言自明的
JSONDecoder().decode(/* swift here is expecting class or struct that conforms to Codable */.self, from: data)
但让我们假设您可以通过协议
在你的协议中
protocol Sticker: Codable {
}
您期望 swift 从数据中解码的属性在哪里?
您在
中添加了属性
public struct StickerString: Sticker, Codable, Equatable { // it should have redundendant conformance as well as you are conforming to Coddle again
let fontName: String // here is the properties you are expected to be decoded with the coding keys
let character: String // here is the properties you are expected to be decoded with the coding keys
}
只要您希望解码的类型是动态的,我建议您这样做
class GenericService< /* here you can pass your class or struct that conforms to Codable */ GenericResponseModel: Codable> {
func buildObjectFromResponse(data: Data?) -> GenericResponseModel? {
var object : GenericResponseModel?
do {
object = try JSONDecoder().decode(GenericResponseModel.self , from: data!)
} catch (let error){
print(error)
}
return object
}
}
- 通过这个class你可以传递任何符合 Codable
的类型甚至列表
- 然后你将使用下面的方法将类型检查与解码过程分离
private func handleDecodingTypes (stickers: [Sticker]){
for sticker in stickers {
if sticker is StickerString {
/* do the decoding here */
}
if sticker is StickerBitmap {
/* do the decoding here */
}
}
}
Sticker协议不是confirming/implementingCodable,它其实是继承自Codable。正如错误消息所暗示的,协议不符合其他协议,只有具体类型符合。
protocol Sticker: Codable //This is Protocol inheritance
通过陈述
public struct StickerString: Sticker
表示Sticker字符串符合Sticker,Sticker是Codable的child,所以StickerString最终符合Codable。无需再次声明一致性,即:
public struct StickerString: Sticker, Codable //Conformance to Codable is redundant
现在进入解码部分。
let recentStickers = try? JSONDecoder().decode([Sticker].self, from: data)
解码方法需要具体类型。它没有关于底层类型或其属性的任何信息,因为 Sticker 本身只是一个协议,它继承自没有 properties/attributes 的 Codable。
编译器在解码后组合 StrickerString 和 StickerBitmap 不会有任何问题,例如
let stickerString = try JSONDecoder().decode(StickerString.self, from: data)
let stickerBitmap = try JSONDecoder().decode(StickerBitmap.self, from: data)
let stickers : [Sticker] = [stickerString, stickerBitmap]
在应用程序中,我们有两种类型的贴纸,字符串和位图。每个贴纸包都可以包含两种类型。这就是我声明模型的方式:
// 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
中,以便我们可以向他显示 "Recently Used" 贴纸选项卡。我正在尝试解码保存的 [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
我不明白为什么我将 Sticker
声明为 Codable
而它也实现了 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)
要解码 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)
在 table 视图中 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
}
}
这里发生的事情是不言自明的
JSONDecoder().decode(/* swift here is expecting class or struct that conforms to Codable */.self, from: data)
但让我们假设您可以通过协议 在你的协议中
protocol Sticker: Codable {
}
您期望 swift 从数据中解码的属性在哪里?
您在
中添加了属性public struct StickerString: Sticker, Codable, Equatable { // it should have redundendant conformance as well as you are conforming to Coddle again
let fontName: String // here is the properties you are expected to be decoded with the coding keys
let character: String // here is the properties you are expected to be decoded with the coding keys
}
只要您希望解码的类型是动态的,我建议您这样做
class GenericService< /* here you can pass your class or struct that conforms to Codable */ GenericResponseModel: Codable> {
func buildObjectFromResponse(data: Data?) -> GenericResponseModel? {
var object : GenericResponseModel?
do {
object = try JSONDecoder().decode(GenericResponseModel.self , from: data!)
} catch (let error){
print(error)
}
return object
}
}
- 通过这个class你可以传递任何符合 Codable 的类型甚至列表
- 然后你将使用下面的方法将类型检查与解码过程分离
private func handleDecodingTypes (stickers: [Sticker]){
for sticker in stickers {
if sticker is StickerString {
/* do the decoding here */
}
if sticker is StickerBitmap {
/* do the decoding here */
}
}
}
Sticker协议不是confirming/implementingCodable,它其实是继承自Codable。正如错误消息所暗示的,协议不符合其他协议,只有具体类型符合。
protocol Sticker: Codable //This is Protocol inheritance
通过陈述
public struct StickerString: Sticker
表示Sticker字符串符合Sticker,Sticker是Codable的child,所以StickerString最终符合Codable。无需再次声明一致性,即:
public struct StickerString: Sticker, Codable //Conformance to Codable is redundant
现在进入解码部分。
let recentStickers = try? JSONDecoder().decode([Sticker].self, from: data)
解码方法需要具体类型。它没有关于底层类型或其属性的任何信息,因为 Sticker 本身只是一个协议,它继承自没有 properties/attributes 的 Codable。 编译器在解码后组合 StrickerString 和 StickerBitmap 不会有任何问题,例如
let stickerString = try JSONDecoder().decode(StickerString.self, from: data)
let stickerBitmap = try JSONDecoder().decode(StickerBitmap.self, from: data)
let stickers : [Sticker] = [stickerString, stickerBitmap]