使用协议类型属性对结构进行解码/编码 [英] Decoding/Encoding a struct with protocol type properties
问题描述
我正在尝试使用 UserDefaults
保存配置数据结构,因此该数据结构需要符合 Codable
协议。这是我的数据结构:
I am trying to save a configuration data structure with UserDefaults
, thus the data structure needs to conform to the Codable
protocol. This is my data structure:
// Data structure which saves two objects, which conform to the Connection protocol
struct Configuration {
var from: Connection
var to: Connection
}
protocol Connection: Codable {
var path: String { get set }
}
// Two implementations of the Connection protocol
struct SFTPConnection: Connection, Codable {
var path: String
var user: String
var sshKey: String
}
struct FTPConnection: Connection, Codable {
var path: String
var user: String
var password: String
}
如果我只添加 Codable
到配置
,它将无法正常工作。因此,我必须自己实现它。
If I just add Codable
to Configuration
, it won't work. So I have to implement it myself.
extension Configuration: Codable {
enum CodingKeys: String, CodingKey {
case from, to
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let from = try container.decode(Connection.self, forKey: .from)
let to = try container.decode(Connection.self, forKey: .to)
self.from = from
self.to = to
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(from, forKey: .from)
try container.encode(to, forKey: .to)
}
}
每次调用 decode()
或 encode()
我收到错误协议类型'Connection'不符合'Decodable / Encodable',因为只有具体类型才能符合协议
。
For every call on decode()
or encode()
I get the error Protocol type 'Connection' cannot conform to 'Decodable/Encodable' because only concrete types can conform to protocols
.
我看到编译器很难识别哪个类应该用于解码给定的对象。但是我认为对对象进行编码应该很容易,因为每个 Connection
类型的对象都实现了 encode()
方法。
I can see that it is difficult for the compiler to identify, which class should be used to decode the given object. But I figured it should be easy to encode an object, since every object of type Connection
implements the encode()
method.
我知道,问题出在协议上,该协议不能与可解码/可编码$ c $一起使用c>。我将如何更改
decode / encode
中的代码,以便仍可以在各种实现中使用该协议?我的猜测是要以某种方式告诉 decode / encode
使用哪种协议实现。对于这个问题,我将不胜感激!
I know, that the problem lies with the protocol and that the protocol can't be used with Decodable/Encodable
. How would I change the code in decode/encode
, so that I can still use the protocol with the various implementations? My guess is to somehow tell decode/encode
which implementation of the protocol to use. I would appreciate any elegant solutions for this problem!
推荐答案
Swift的一个局限是协议不能符合自身。因此,从到
到
的不符合
Codable
好像那样。
It's a limitation of Swift that a protocol cannot conform to itself. Thus from
and to
do not conform to Codable
as bizarre as that seems.
您可以使用泛型来解决它,这基本上意味着您声明了 from
和 to
作为符合 Codable
的任意类型。方法如下:
You can get around it by using generics which basically means you declare from
and to
as arbitrary types that conform to Codable
. Here's how:
struct Configuration<F: Connection, T: Connection>: Codable {
var from: F
var to: T
}
let myFrom = SFTPConnection(path: "foo", user: "me", sshKey: "hgfnjsfdjs")
let myTo = FTPConnection(path: "foo", user: "me", password: "hgfnjsfdjs")
let example = Configuration(from: myFrom, to: myTo)
所以 F
和 T
是符合 Connection
的类型。在最后一行中实例化 example
时,编译器推断 F
是 SFTPConnection
和 T
是 FTPConnection
。
So F
and T
are types that conform to Connection
. When you instantiate example
in the last line, the compiler infers F
is SFTPConnection
and T
is FTPConnection
.
一旦添加了通用参数,配置
就能够在没有扩展名的情况下综合到 Codable
的一致性。
Once I added the generic parameters, Configuration
was able to synthesise the conformance to Codable
without the extension.
为了回答Sh_kahn关于具有两个通用参数的观点,我这样做是为了允许 from
和至
是不同类型的连接。如果您始终希望两个连接具有相同的类型,即总是两个 SFTPConnection
或两个 FTPConnection
像这样声明 Configuration
:
To answer Sh_kahn's point about having two generic parameters, I did this to allow from
and to
to be connections of different types. If you always want the two connections to be of the same type i.e. always two SFTPConnection
s or two FTPConnection
s you should declare the Configuration
like this:
struct Configuration<C: Connection>: Codable {
var from: C
var to: C
}
这篇关于使用协议类型属性对结构进行解码/编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!