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?.a
或dictionary?.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
}
}
}