简体   繁体   English

Swift 4 Codable对象的集合

[英]Swift 4 collection of Codable objects

I have a Codable class with a variable that holds a dictionary with String keys and values that may be String s, Int s or custom structs conforming to Codable . 我有一个Codable类,其中包含一个包含String键和值的字典,该String可以是String s, Int s或符合Codable自定义结构。 My question is: 我的问题是:

How do I define a dictionary with values that are Codable ? 如何定义具有可Codable值的字典?

I hoped it would be enough to say 我希望这足以说明

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

but apparently that makes my class no longer conform to Codable . 但显然这使我的班级不再符合Codable I think the problem here is the same as I had here, where I am passing a protocol rather than an object constrained by the protocol 我认为这里的问题与我在这里的问题相同,我传递协议而不是协议约束的对象

Using JSON Encoder to encode a variable with Codable as type 使用JSON编码器对Codable作为类型的变量进行编码

So presumably I would need a constrained generic type, something like AnyObject<Codable> but that's not possible. 所以我可能需要一个约束泛型类型,比如AnyObject<Codable>但这是不可能的。

EDIT: Answer 编辑:答案

So since this can't be done as per the accepted answer, I am resorting to a struct with dictionaries for each data type 因此,由于这不能按照接受的答案进行,所以我使用的是每个数据类型都有字典的结构

struct CodableData {
    var ints: [String: Int]
    var strings: [String: String]
    //...

    init() {
       ints = [:]
       strings = [:]
    }
}

var data = CodableData()

A Swift collection contains just one type, and for it to be Codable, that type would need to be Codable — not Codable the type, but an adopter of the Codable protocol. Swift集合只包含一种类型,并且对于它是Codable,该类型需要是Codable - 不是Codable类型,而是Codable协议的采用者 You need the type here to be some one specific Codable adopter . 你需要这里的类型是一个特定的Codable采用者

Therefore the only way to do what you're describing would be basically to invent some new type, StringOrIntOrStruct, that wraps a String or an Int or a struct and itself adopts Codable. 因此,执行您所描述的内容的唯一方法是基本上发明一些新类型StringOrIntOrStruct,它包装String或Int或结构,并且本身采用Codable。

But I don't think you're doing to do that, as the effort seems hardly worth it. 但我不认为你这样做,因为努力似乎不值得。 Basically, you should stop trying to use a heterogeneous Swift collection in the first place; 基本上,你应该首先停止尝试使用异构的Swift集合; it's completely against the spirit of the language. 这完全违背了语言的精神。 It's a Bad Smell from the get-go. 从一开始就是一种糟糕的气味。 Rethink your goals. 重新思考你的目标。

I think the compiler is simply not smart enough to infer the Codable implementation automatically. 我认为编译器根本不够聪明,无法自动推断Codable实现。 So one possible solution is to implement Codable by hand: 因此,一种可能的解决方案是手动实现Codable

class Foo: Codable {

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

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

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

I don't know whether you can change the data type to help the compiler do the work for you. 我不知道您是否可以更改data类型以帮助编译器为您完成工作。 At least you can pull the hand-coding to the problematic type: 至少你可以将手动编码拉到有问题的类型:

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] = [:]
}

Have any of you tried Generics in Swift? 有没有人在Swift中尝试过Generics? Look: 看:

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]?
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM