gpt4 book ai didi

swift - 使用 @dynamicMemberLookup 访问 AnyCodable 值

转载 作者:搜寻专家 更新时间:2023-10-31 23:06:09 53 4
gpt4 key购买 nike

Objc.io有一个很好的关于轻松改变无类型字典的演讲,但问题是你不能轻易地坚持他们。我认为该演讲可能在引入 @dynamicMemberLookup 之前发布。

AnyCodable轻松编码/解码/保留简单的字典看起来很棒,但您无法轻松访问字典成员。

我想知道将 Swift 4.2 中的 @dynamicMemberLookup 功能(例如:在 this example 中)添加到 AnyCodable 是否可能/可行,如果可以,怎么做? 最终目标是访问/改变未类型化的数组或字典持久化它们。

所以,我试着这样做:

@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] 而不是展开 nested首先是 if let nested = dictionary["nested"]并且我希望能够改变它,例如:dictionary?.nested?.a? =“测试版”

虽然我不知道如何让它越过终点线。我显然需要添加 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
}
}
}

关于swift - 使用 @dynamicMemberLookup 访问 AnyCodable 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54735576/

53 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com