Swift 解码/编码具有协议类型属性的结构

Swift 解码/编码具有协议类型属性的结构,swift,encoding,protocols,decode,codable,Swift,Encoding,Protocols,Decode,Codable,我试图用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 { va

我试图用
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()
的每次调用,我都会得到错误
协议类型“连接”不能符合“可解码/可编码”,因为只有具体类型才能符合协议

我可以看出,编译器很难确定应该使用哪个类来解码给定的对象。但是我认为编码一个对象应该很容易,因为
Connection
类型的每个对象都实现了
encode()
方法


我知道,问题在于协议,协议不能与
可解码/可编码
一起使用。如何更改
解码/编码
中的代码,以便在各种实现中仍能使用协议?我的猜测是以某种方式告诉
解码/编码
使用哪个协议实现。我将感谢任何优雅的解决方案,这个问题

Swift的一个限制是协议不能符合自身。因此,从
到的
可编码的
似乎并不一致

您可以通过使用泛型来绕过它,泛型基本上意味着您将
from
to
声明为符合
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)


Swift的一个限制是协议不能符合自身。因此,从
到的
可编码的
似乎并不一致

您可以通过使用泛型来绕过它,泛型基本上意味着您将
from
to
声明为符合
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)



错误是正确的:
Codable
需要符合
Codable
的具体类。除了泛型之外没有其他解决方法,泛型实际上在代码执行时提供了一个具体的类型。谢谢,你能用泛型更详细地解释一下这个想法吗?见Jeremy的答案。这正是我的意思我假设问题中有一个输入错误:协议被定义为
连接
,但在扩展中,它被称为
连接配置
谢谢,当我试图为一个问题简化代码时就会发生这种情况……错误是正确的:
Codable
需要符合
Codable
的具体类。除了泛型之外没有其他解决方法,泛型实际上在代码执行时提供了一个具体的类型。谢谢,你能用泛型更详细地解释一下这个想法吗?见Jeremy的答案。这正是我的意思我假设问题中有一个输入错误:协议被定义为
连接
,但在扩展中,它被称为
连接配置
谢谢,当我试图简化一个问题的代码时,就会发生这种情况……这与将它们设置为属性没有区别,而且您可以重复相同的
1@Sh_Khan制作什么属性?我使用了两个通用参数,因此
from
属性可以是与
to
属性不同的类型。谢谢,这样就解决了问题。但是我想从
UserDefaults
加载所有
Configuration
对象,这些对象可能都有不同类型的
F
T
?我将调用
func loadAll()->[String:Configuration]?{return UserDefaults.standard.dictionaryRepresentation()as?[String:Configuration]}
但这不起作用,因为每个配置都可能有不同的
F
t
@Codey我不知道如何解决这个问题。当你开始解码时,你已经进入了对象的
init
,这意味着
F
T
已经被选中。这可能是使用类和继承的情况。但我建议你写一个新问题。@JeremyP我为这个问题贴了一个新问题:。如果你能看一下,我将不胜感激。不过,谢谢你的回答!这与使它们成为属性没有区别,你也可以重复相同的
1@Sh_Khan制作什么属性?我使用了两个通用参数,因此
from
属性可以是与
to
属性不同的类型。谢谢,这样就解决了问题。但是我想从
UserDefaults
加载所有
Configuration
对象,这些对象可能都有不同类型的
F
T
?我将调用
func loadAll()->[String:Configuration]?{return UserDefaults.standard.dictionaryRepresentation()as?[String:Configuration]}
但这不起作用,因为每个配置都可能有不同的
F
t
@Codey我不知道如何解决这个问题。当你开始解码时,你已经进入了对象的
init
,这意味着
F
T
已经被选中。这可能是使用类和继承的情况。但我建议你写一个新问题。@JeremyP我为这个问题贴了一个新问题:。如果你能看一下,我将不胜感激。不过,谢谢你的回答!