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



我正在尝试使用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中的代码,以便我仍然可以在各种实现中使用该协议?我的猜测是以某种方式告诉decode/encode使用哪种协议实现。我将不胜感激这个问题的任何优雅解决方案!

这是 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时,编译器会推断FSFTPConnectionTFTPConnection

添加通用参数后,Configuration能够在没有扩展的情况下合成Codable一致性。


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

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

相关内容

  • 没有找到相关文章

最新更新