Swift 4 Codable对象的集合

时间:2017-08-17 12:02:19

标签: ios swift dictionary generics protocols

我有一个Codable类,其中包含一个变量,该变量包含一个带有String个字符的字典,值可能是String s,Int s或符合{的自定义结构{1}}。我的问题是:

如何定义值为Codable的字典?

我希望能够说

Codable

但显然这使我的班级不再符合var data: [String: Codable] = [:] 。我认为这里的问题和我在这里的问题一样,我传递协议而不是协议约束的对象

  

Using JSON Encoder to encode a variable with Codable as type

所以我可能需要一个约束泛型类型,比如Codable,但这是不可能的。

编辑:回答

因此,由于这不能按照接受的答案完成,所以我采用的是每个数据类型都有字典的结构

AnyObject<Codable>

3 个答案:

答案 0 :(得分:2)

Swift集合只包含一种类型,并且它可以是Codable,该类型需要是Codable - 不是Codable类型,而是Codable协议的采用者。您需要此类型为一个特定的Codable采用者

因此,执行您所描述的内容的唯一方法是基本上发明一些新类型StringOrIntOrStruct,它包装String或Int或结构,并且本身采用Codable。

但我不认为你这样做是因为努力似乎不值得。基本上,你应该首先停止尝试使用异构的Swift集合;这完全违背了语言的精神。从一开始就是一种糟糕的气味。重新思考你的目标。

答案 1 :(得分:1)

我认为编译器不够聪明,不能自动推断Codable实现。因此,一种可能的解决方案是手动实施Codable

class Foo: Codable {

    var data: [String:Codable] = [:]

    func encode(to encoder: Encoder) throws {
        // ...
    }

    required init(from decoder: Decoder) throws {
        // ...
    }
}

我不知道您是否可以更改data类型以帮助编译器为您完成工作。至少你可以将手动编码拉到有问题的类型:

enum Option: Codable {

    case number(Int)
    case string(String)

    func encode(to encoder: Encoder) throws {
        // ...
    }

    init(from decoder: Decoder) throws {
        if let num = try? Int(from: decoder) {
            self = .number(num)
        } else if let str = try? String(from: decoder) {
            self = .string(str)
        } else {
            throw something
        }
    }
}

class Foo: Codable {

    var data: [String:Option] = [:]
}

答案 2 :(得分:0)

有没有人在Swift中尝试过Generics? 看:

public struct Response<T> where T : Codable {
        let ContentEncoding : String?
        let ContentType : String?
        let JsonRequestBehavior : Int?
        let MaxJsonLength : Int?
        let RecursionLimit : Int?

        let data : Data?

        public struct Data : Codable {
            let response : String?
            let status : String?

            let details : [T]?
        }
    }