使用协议类型属性对结构进行解码/编码 [英] Decoding/Encoding a struct with protocol type properties

查看:143
本文介绍了使用协议类型属性对结构进行解码/编码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 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.

我知道,问题出在协议上,该协议不能与可解码/可编码。我将如何更改 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 SFTPConnections or two FTPConnections you should declare the Configuration like this:

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

这篇关于使用协议类型属性对结构进行解码/编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆