Ios Swift:解码任意协议类型

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:彻底检查

我试图解码JSON,它有一个符合协议的变量属性

考虑以下一组结构:

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
的字段是什么是不够的。它需要准确地知道解码为哪种类型。