Ios Swift:解码任意协议类型
我试图解码JSON,它有一个符合协议的变量属性 考虑以下一组结构:Ios Swift:解码任意协议类型,ios,swift,Ios,Swift,我试图解码JSON,它有一个符合协议的变量属性 考虑以下一组结构: P协议:可解码{ 变量id:字符串{get} } 结构A:P{ let id:String 什么东西:双倍 } 结构B:P{ let id:String 另一件事:字符串 } 结构S:可解码{ let id:String 让instanceOfProtocol:P } 我们正在尝试解码S Decodable的自动合成不起作用(因为解码器不知道将解码到哪种类型的p),所以我尝试在自定义初始值设定项中执行此操作: 选项1:彻底检查
P协议:可解码{
变量id:字符串{get}
}
结构A:P{
let id:String
什么东西:双倍
}
结构B:P{
let id:String
另一件事:字符串
}
结构S:可解码{
let id:String
让instanceOfProtocol:P
}
我们正在尝试解码S
Decodable
的自动合成不起作用(因为解码器不知道将解码到哪种类型的p
),所以我尝试在自定义初始值设定项中执行此操作:
选项1:彻底检查合格类型:
如果让instance=try?container.decode(A.self,forKey:.instanceOfProtocol){
InstanceOffProtocol=实例
}如果让instance=try?container.decode(B.self,forKey:.instanceOfProtocol){
InstanceOffProtocol=实例
}否则{
抛出NoConformingTypeError()
}
这是可行的,但是非常冗长、重复,并且不能很好地扩展,所以我正在寻找其他的选择
选项2:(Ab)使用超级解码器
:
let possibleTypes:[P.Type]=[A.self,B.self]
let childDecoder=try container.superDecoder(forKey:.instanceOfProtocol)
let decoded:[P]=possibleTypes.compactMap{try?$0.init(from:childDecoder)}
guard let instance=decoded.first-else{throw NoConformingTypeError()}
InstanceOffProtocol=实例
这也很有效,但我不确定超级解码器是否打算以这种方式使用,或者它将来是否会崩溃
备选案文3:
let possibleTypes:[P.Type]=[A.self,B.self]
let decoded:[P]=possibleTypes.compactMap{try?container.decode($0,forKey:.instanceOfProtocol)}
guard let instance=decoded.first-else{throw NoConformingTypeError()}
InstanceOffProtocol=实例
到目前为止,这似乎是最好的选择,但由于对成员“decode(uquo:forKey:)”
的引用不明确,因此无法编译
编辑:
选项4:使用泛型类型:
structs:Decodable{
let id:String
让实例fprotocol:T
}
这真的很好,因为可解码
的合成再次起作用
但是,现在我们必须知道T
将是什么类型,因为解码站点现在需要一种类型:
尝试JSONDecoder()。解码(S.self,from:data)
尝试JSONDecoder()。解码(S.self,from:data)
在我们的用例中,我们无法知道之前的类型是什么,因此我们必须再次检查这里…使用泛型类型:
struct S<T: P>: Decodable {
let id: String
let instanceOfProtocol: T
}
structs:Decodable{
let id:String
让实例fprotocol:T
}
请记住
协议
不是类型
!Swift是强类型语言。因此,它必须首先知道所有对象的类型,即使实际类型不可向对象的调用者公开。我忘了提到我以前尝试过。虽然这很好(因为可以合成可解码的
),但它只是将类型消歧移到调用站点:try?JSONDecoder().decode(S.self,from:json1)
如果您不知道之前的类型是什么,那么您就无法将其解码为众所周知的类型。因为您根本无法检查世界上所有的可解码类型。应该有东西告诉你什么类型是枚举之类的。你在这里注意到的是名义上的((角色或状态)只存在于名义上的)类型和结构类型之间的区别。JSON是结构化类型的。每个对象的类型实际上只是其场的反射。如果两个对象具有相同的字段,则可以认为它们具有相同的类型。在Swift中情况并非如此,类型的名称是它们唯一的身份来源。Swift要知道如何解码P
,只知道P
的字段是什么是不够的。它需要准确地知道解码为哪种类型。