使用@dynamicmemberlookup访问任何可编码的值



objc.io就容易突变的词典进行了很好的演讲,但是问题是您无法轻易持续存在。我认为谈话可能是在引入@dynamicMemberLookup之前发布的。

任何可编码看起来很棒,可以轻松编码/解码/持续简单词典,但您无法轻松访问字典成员。

我想知道是否有可能/可行的是,在Swift 4.2(例如,在此示例中)中发现的@dynamicMemberLookup功能是否可以编码,如果是的话,如何?最终目标是访问/突变一个未型数组或字典坚持下去。

所以,我尝试这样做:

@dynamicMemberLookup
public struct AnyCodable: Codable {
    public let value: Any
    public init<T>(_ value: T?) {
        self.value = value ?? ()
    }
    subscript(dynamicMember member: String) -> AnyCodable? {
        switch self.value {
        case let dictionary as [String: Any?]:
            return AnyCodable(dictionary[member])
        default:
            return nil
        }
    }
}

给出了 AnyCodable的示例字典:

let dictionary: [String: AnyEncodable] = [
    "boolean": true,
    "integer": 1,
    "double": 3.14159265358979323846,
    "string": "string",
    "array": [1, 2, 3],
    "nested": [
        "a": "alpha",
        "b": "bravo",
        "c": "charlie"
    ]
]

如果我这样做:

if let nested = dictionary["nested"] {
    print("nested a:", nested.a)
}

它输出:几乎存在的nested a: Optional(AnyCodable(Optional("alpha")))!但我希望能够简单地编写dictionary?.nested?.adictionary?.array?[1],而不是首先使用if let nested = dictionary["nested"]解开nested我希望能够突变,例如: dictionary?.nested?.a? = "beta"

我不知道如何在整个终点线上获取它。显然,我需要添加 case let array as [Any]:等。也许将下标更改为包括getter/setter?但是我还缺少什么?

我知道您可能"不应该以这种方式使用字典",并创建一个成熟的定制模型等等,但这是针对一个小型项目,而该路线将过于夸张。因此,请不要以"以不同的方式建模数据"回答。我想结合这两种现有的访问/持续使用词典或数组的方法。

好吧,我认为我大部分都覆盖了。

第一个问题是您使用词典。您可以将 @dynamicmemberlookup 添加到主要定义中,因此您不能在字典定义上进行操作。尝试以下操作:

let dictionary: [String: AnyEncodable] = [ ... ]
let easierToUse = AnyCodable(dictionary)

那么考虑下面的代码,是您需要的吗?:

let dictionary: [String: AnyCodable] = [
    "boolean": true,
    "integer": 1,
    "double": 3.14159265358979323846,
    "string": "string",
    "array": [1, 2, 3],
    "nested": [
        "a": "alpha",
        "b": "bravo",
        "c": "charlie",
        "array": [
            1,
            2,
            [
                "a": "alpha",
                "b": "bravo",
                "c": "deep charlie"
            ]
        ],
    ]
]
let easierToUse: AnyCodable = AnyCodable(dictionary)
if let value = easierToUse.nested?.a {
    print(value) // prints "alpha"
}
if let value = easierToUse.nested?.array?[2]?.c {
    print(value) // prints "deep charlie"
}
if let value = easierToUse.nested?.array?[2]?.c?.value as? String {
    print(value) // prints "deep charlie"
}

我不得不更新您的课程,因为您忘记了所有级别都包裹着:

// Helper to handle out of bounds on array with nil
extension Array {
    subscript (safe index: Int) -> Element? {
        return indices ~= index ? self[index] : nil
    }
}
@dynamicMemberLookup
public struct AnyCodable: Codable {
    public let value: Any
    public init<T>(_ value: T) {
        self.value = value
    }
    public init<T>(_ value: T?) {
        self.value = value ?? ()
    }
    subscript(dynamicMember member: String) -> AnyCodable? {
        switch self.value {
        case let anyCodable as AnyCodable:
            return anyCodable[dynamicMember: member]
        case let dictionary as [String: Any?]:
            return AnyCodable(dictionary[member] ?? nil)
        default:
            return nil
        }
    }
    subscript(index: Int) -> AnyCodable? {
        switch self.value {
        case let anyCodable as AnyCodable:
            return anyCodable[index]
        case let array as [Any]:
            return AnyCodable(array[safe: index])
        default:
            return nil
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新