繁体   English   中英

Swift:解码任意协议类型

[英]Swift: Decode arbitrary protocol types

我正在尝试解码具有符合协议的可变属性的JSON。

考虑以下结构集:

protocol P: Decodable {
    var id: String { get }
}

struct A: P {
    let id: String
    var someThing: Double
}

struct B: P {
    let id: String
    var anotherThing: String
}

struct S: Decodable {
    let id: String
    let instanceOfProtocol: P
}

我们正在尝试解码S

Decodable的自动综合无法正常工作(因为解码器无法知道P将被解码为哪种类型),所以我尝试在自定义初始化程序中执行以下操作:

选项1:详尽检查符合类型:

if let instance = try? container.decode(A.self, forKey: .instanceOfProtocol) {
    instanceOfProtocol = instance
} else if let instance = try? container.decode(B.self, forKey: .instanceOfProtocol) {
    instanceOfProtocol = instance
} else {
    throw NoConformingTypeError()
}

这可行,但是非常冗长,重复,并且伸缩性不佳,因此我正在寻找其他选择。

选项2:(Ab)使用superDecoder

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() }
instanceOfProtocol = instance

这也可以正常工作,但是我不确定superDecoder是否打算以这种方式使用,或者将来是否会崩溃。

选项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() }
instanceOfProtocol = instance

到目前为止,这似乎是最好的选择,但由于Ambiguous reference to member 'decode(_:forKey:)'Ambiguous reference to member 'decode(_:forKey:)' ,因此无法编译。

编辑:

选项4:使用通用类型:

struct S<T: P>: Decodable {
    let id: String
    let instanceOfProtocol: T
}

这真是太好了,因为“ Decodable合成再次起作用了!

但是,现在我们必须知道类型T ,因为解码站点现在需要一种类型:

try JSONDecoder().decode(S<A>.self, from: data)
try JSONDecoder().decode(S<B>.self, from: data)

在我们的用例中,我们不知道类型是什么,因此我们必须再次检查这里...

使用通用类型:

struct S<T: P>: Decodable {
    let id: String
    let instanceOfProtocol: T
}

记住Protocol不是Type Swift是强类型语言。 因此,即使对象的调用者无法暴露实际的类型,它也必须首先知道所有对象的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM