【问题标题】:Swift 4 collection of Codable objectsSwift 4 Codable 对象的集合
【发布时间】:2018-01-25 20:08:49
【问题描述】:

我有一个Codable 类,其中包含一个包含String 键和值的字典,可能是Strings、Ints 或符合Codable 的自定义结构。我的问题是:

如何定义具有Codable 值的字典?

我希望这已经足够了

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

但显然这使我的课程不再符合Codable。我认为这里的问题与我在这里的问题相同,我传递的是协议而不是受协议约束的对象

Using JSON Encoder to encode a variable with Codable as type

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

编辑:回答

因此,由于无法按照公认的答案完成此操作,因此我采用了一个结构,其中包含每种数据类型的字典

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

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

var data = CodableData()

【问题讨论】:

  • 这与 Codable 有什么关系?这真的不是关于 Swift 中的协议和类型吗?
  • 这里的问题是您使用Codable 作为字典中的存在类型。你是对的,你需要将类型限制为某种东西,但即使AnyObject<Codable> 也不会是它——你需要一些具体的,比如IntString。您的字典将包含的类型是否有限制?你预计解码会发生什么?

标签: ios swift dictionary generics protocols


【解决方案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] = [:]
}

【讨论】:

  • 并不是编译器不够聪明,无法为你做这件事——而是你不能调用decode(Codable.self)。正如您所展示的,您需要尝试解码多个 concrete 类型才能实现这一点。
【解决方案2】:

一个 Swift 集合只包含一种类型,并且要使其成为 Codable,该类型需要是 Codable ——不是 Codable 类型,而是 Codable 协议的采用者。您需要此处的类型是某个一个特定的 Codable 采用者

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

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

【讨论】:

  • 谢谢你,马特,看来你是对的。问题是我让用户输入了一堆数据、一些文本、一些日期、一些布尔值等,并且需要将其存储在某个地方。我想我会为我支持的每种类型制作单独的字典
【解决方案3】:

你们中有人在 Swift 中尝试过泛型吗? 看:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    相关资源
    最近更新 更多