使用协议类型属性对结构进行解码/编码

时间:2019-12-16 09:10:45

标签: swift encoding protocols decode codable

我正在尝试使用select * from test_13102019 limit 10;保存配置数据结构,因此该数据结构需要符合UserDefaults协议。这是我的数据结构:

Codable

如果我仅将// 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,它将无法正常工作。所以我必须自己实现。

Configuration

每次致电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()

我看到编译器很难识别应该使用哪个类来解码给定的对象。但是我认为对对象进行编码应该很容易,因为每个Protocol type 'Connection' cannot conform to 'Decodable/Encodable' because only concrete types can conform to protocols类型的对象都实现了Connection方法。

我知道,问题出在协议上,并且该协议不能与encode()一起使用。我将如何更改Decodable/Encodable中的代码,以便仍然可以在各种实现中使用该协议?我的猜测是要以某种方式告诉decode/encode使用该协议的哪种实现。对于这个问题,我将不胜感激!

1 个答案:

答案 0 :(得分:2)

Swift的局限性在于协议无法遵循自身。因此,fromto似乎并不像Codable那样奇怪。

您可以通过使用泛型来解决它,这基本上意味着您将fromto声明为符合Codable的任意类型。方法如下:

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)

因此FT是符合Connection的类型。在最后一行中实例化example时,编译器推断FSFTPConnection,而TFTPConnection

一旦我添加了通用参数,Configuration就能够在没有扩展名的情况下综合符合Codable的情况。


要回答Sh_kahn关于具有两个通用参数的观点,我这样做是为了允许fromto是不同类型的连接。如果您始终希望两个连接具有相同的类型,即总是两个SFTPConnection或两个FTPConnection,则应这样声明Configuration

struct Configuration<C: Connection>: Codable {
    var from: C
    var to: C
}