下标:使用String枚举访问我的字典值

时间:2016-09-14 20:28:58

标签: ios swift dictionary overloading subscript

我想做类似的事情:使用String枚举访问我的字典值。我试图重写字典的下标,但没有成功。

访问字典:

let district = address[JsonKeys.district]

JsonKeys在哪里:

enum JsonKeys: String {
    case key1
    case key2
    case key...
}

和我的下标重载如下:

extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
    subscript(index: FOJsonKeys) -> AnyObject {
        get {
            return self[ index.rawValue] as! AnyObject
        }
    }
}

我收到以下消息:

**Cannot subscript a value of type 'Dictionary<Key, Value>' with an index of type 'String'**

我哪里错了?

PS:不想这样做(这会纠正错误,但代码是不可读的):

let district = address[JsonKeys.district.rawValue]

字典是AlamoFire给我的Json解析字典。我很确定我不能改变它的类型。

3 个答案:

答案 0 :(得分:3)

最简单的方法是将字典提升到更多上下文中。在这种情况下的上下文是“它只有来自此枚举的键。”在Swift中提升类型非常简单。只需将其包装在结构中即可。

// This could be a nested type inside JSONObject if you wanted.
enum JSONKeys: String {
    case district
}

// Here's my JSONObject. It's much more type-safe than the dictionary,
// and it's trivial to add methods to it.
struct JSONObject {
    let json: [String: AnyObject]
    init(_ json: [String: AnyObject]) {
        self.json = json
    }

    // You of course could make this generic if you wanted so that it
    // didn't have to be exactly JSONKeys. And of course you could add
    // a setter.
    subscript(key: JSONKeys) -> AnyObject? {
        return json[key.rawValue]
    }
}

let address: [String: AnyObject] = ["district": "Bob"]

// Now it's easy to lift our dictionary into a "JSONObject"
let json = JSONObject(address)

// And you don't even need to include the type. Just the key.
let district = json[.district]

答案 1 :(得分:2)

试试这个:

extension Dictionary where Key: StringLiteralConvertible {
    subscript(index: JsonKeys) -> Value {
        get {
            return self[index.rawValue as! Key]!
        }
    }
}

请注意,如果约束为Key: StringLiteralConvertible,则扩展程序适用于任何字典符合StringLiteralConvertible的字典。 (您知道String以外的许多类型符合StringLiteralConvertible。)

要调用下标self[],您需要传递Key类型的值。 index.rawValueString,在扩展程序中可能并不总是Key

因此,我展示的扩展名适用于某些词典,会导致某些其他词典的运行时崩溃。

更加类型安全的方式:

protocol MyJsonKeysConvertible {
    init(jsonKeys: JsonKeys)
}
extension String: MyJsonKeysConvertible {
    init(jsonKeys: JsonKeys) {self = jsonKeys.rawValue}
}
extension Dictionary where Key: MyJsonKeysConvertible {
    subscript(index: JsonKeys) -> Value {
        get {
            return self[Key(jsonKeys: index)]!
        }
    }
}

答案 2 :(得分:0)

我知道这是一个老问题,但我想我会添加一个更容易扩展,重用和更轻量级的实现

public protocol UsesRawValue {
    var rawValue: String { get }
}

extension JsonKeys: UsesRawValue {}

extension Dictionary where Key: ExpressibleByStringLiteral {
    public subscript(key: UsesRawValue) -> Value? {
        get { return self[key.rawValue as! Key] }
        set { self[key.rawValue as! Key] = newValue }
    }
}

Based on this blog post

这种方法只需要我们扩展一次字典,而不是每个枚举。相反,每个枚举都需要符合UsesRawValue。现在我们可以像这样使用它。

ajson[JsonKeys.key1]
ajson[JsonKeys.key1] = "name"