[英]Decoding/Encoding a struct with protocol type properties
I am trying to save a configuration data structure with UserDefaults
, thus the data structure needs to conform to the Codable
protocol.我正在尝试使用
UserDefaults
保存配置数据结构,因此数据结构需要符合Codable
协议。 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
}
If I just add Codable
to Configuration
, it won't work.如果我只是将
Codable
添加到Configuration
,它将不起作用。 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)
}
}
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
.对于
decode()
或encode()
每次调用,我都会收到错误Protocol type 'Connection' cannot conform to 'Decodable/Encodable' because only concrete types can conform to protocols
。
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.但我认为对对象进行编码应该很容易,因为
Connection
类型的每个对象都实现了encode()
方法。
I know, that the problem lies with the protocol and that the protocol can't be used with Decodable/Encodable
.我知道,问题出在协议上,并且该协议不能与
Decodable/Encodable
一起使用。 How would I change the code in decode/encode
, so that I can still use the protocol with the various implementations?我将如何更改
decode/encode
的代码,以便我仍然可以将协议与各种实现一起使用? My guess is to somehow tell decode/encode
which implementation of the protocol to use.我的猜测是以某种方式告诉
decode/encode
要使用的协议实现。 I would appreciate any elegant solutions for this problem!我很感激这个问题的任何优雅的解决方案!
It's a limitation of Swift that a protocol cannot conform to itself. Swift 的一个限制是协议不能符合自身。 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
.您可以通过使用泛型来绕过它,这基本上意味着您将
from
和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)
So F
and T
are types that conform to Connection
.所以
F
和T
是符合Connection
类型。 When you instantiate example
in the last line, the compiler infers F
is SFTPConnection
and T
is FTPConnection
.当您在最后一行实例化
example
时,编译器推断F
是SFTPConnection
而T
是FTPConnection
。
Once I added the generic parameters, Configuration
was able to synthesise the conformance to Codable
without the extension.一旦我添加了通用参数,
Configuration
就能够在没有扩展的情况下综合符合Codable
。
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.要回答Sh_kahn的大约有两个通用的参数来看,我这样做是为了让
from
和to
是两种不同类型的连接。 If you always want the two connections to be of the same type ie always two SFTPConnection
s or two FTPConnection
s you should declare the Configuration
like this:如果您总是希望两个连接的类型相同,即总是两个
SFTPConnection
或两个FTPConnection
您应该像这样声明Configuration
:
struct Configuration<C: Connection>: Codable {
var from: C
var to: C
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.