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