swift - 使用 @dynamicMemberLookup 访问 AnyCodable 值
问题描述
Objc.io有一个关于轻松改变无类型字典的精彩演讲,但问题是你不能轻易地持久化它们。我认为演讲可能在介绍之前已经发布@dynamicMemberLookup
。
AnyCodable看起来很棒,可以轻松编码/解码/保存简单的字典,但您不能轻松访问字典成员。
@dynamicMemberLookup
我想知道将Swift 4.2 中的功能(例如:在此示例中)添加到 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?.a
ORdictionary?.array?[1]
而不是nested
先用if let nested = dictionary["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
}
}
}
推荐阅读
- python - PanclusGz 没有属性 date_solareclipse
- regex - 正则表达式获取带有破折号和正斜杠的 URL 的文件名
- express - 无法推送元素类型 ObjectId 的猫鼬数组
- c - c语言的函数定积分
- c - freeglut (./a.out): 错误: 没有为窗口 1 注册显示回调
- visual-studio - 没有办法解决之间的冲突 - 警告
- angular - 在 VSCode 中调试 Angular 应用程序再次无法正常工作
- flutter - 因为sdk的flutter_driver每个版本都依赖crypto 2.1.5,Cruise依赖crypto 3.0.0,所以sdk的flutter_driver是被禁止的
- javascript - 在 Html/CSS/JS 中将文本格式化到图像的右侧
- python - PHP调用python脚本但不返回结果