Swift 使用@dynamicMemberLookup访问任意可编码值
关于易变异的非类型化词典有一个很好的讨论,但问题是你不能轻易地将它们持久化。我想这次演讲可能是在Swift 使用@dynamicMemberLookup访问任意可编码值,swift,persistence,codable,swift4.2,untyped-variables,Swift,Persistence,Codable,Swift4.2,Untyped Variables,关于易变异的非类型化词典有一个很好的讨论,但问题是你不能轻易地将它们持久化。我想这次演讲可能是在@dynamicMemberLookup推出之前发布的 简单字典的编码/解码/持久化看起来很棒,但您无法轻松访问字典成员 我想知道是否有可能/可行将Swift 4.2(例如:in)中的@dynamicMemberLookup功能添加到任何可编码表中,如果有,如何添加最终目标是访问/变异非类型化数组或字典并将其持久化。 所以,我试着这样做: @dynamicMemberLookup public str
@dynamicMemberLookup
推出之前发布的
简单字典的编码/解码/持久化看起来很棒,但您无法轻松访问字典成员
我想知道是否有可能/可行将Swift 4.2(例如:in)中的@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
}
}
}
如果我这样做:
if let nested = dictionary["nested"] {
print("nested a:", nested.a)
}
它输出:嵌套的a:Optional(AnyCodable(Optional)(“alpha”))
几乎就在那里了!但我希望能够简单地编写dictionary?.nested?.a
或dictionary?.array?[1]
,而不是先用打开nested
,如果让nested=dictionary[“nested”]
。我希望能够对它进行变异,例如:dictionary?.nested?.a?=“测试版”
不过,我不知道怎样才能越过终点线。我显然需要将case-let数组添加为[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
}
}
}
//帮助器在具有nil的数组上处理越界
扩展阵列{
下标(安全索引:Int)->元素{
回报指数~=指数?自[指数]:零
}
}
@动态成员查找
公共结构AnyCodable:Codable{
公共出租价值:任何
公共初始化(u值:T){
自我价值=价值
}
公共初始化(u值:T?){
self.value=值??()
}
下标(dynamicMember成员:String)->AnyCodable{
转换自我价值{
case let anyCodable作为anyCodable:
返回anyCodable[dynamicMember:member]
case let dictionary as[字符串:有吗?]:
返回AnyCodable(字典[成员]??nil)
违约:
归零
}
}
下标(索引:Int)->AnyCodable{
转换自我价值{
case let anyCodable作为anyCodable:
返回anyCodable[索引]
case let数组作为[任何]:
返回AnyCodable(数组[安全:索引])
违约:
归零
}
}
}
太棒了,谢谢!这似乎确实管用!布景怎么样?例如:easierouse.nested?.array?[2]?.c=“not charlie”
为了在dynamicMemberLookup子脚本中使用set{…}
,整个设置是否需要是一个类而不是一个结构?因为AnyCodable
成员是值引用的吗也许你可以保持它的结构,我今天会尝试玩变异的东西。这是一个有点难,因为对于你已经做了大部分时间的获得者work@taber它变得有点太大了,无法粘贴到响应中。我分叉了原始回购协议,并添加了所有dynamicMemberLookup内容。添加了获取/设置值的测试,您可以在:啊,很好!也许我用错了,但是如果我更改并尝试保存示例dict,我会得到一个AnyCodable值cannot encoded
错误。您是否能够保存并加载键入为AnyCodable的示例dict?我的测试代码:var easierToUse:AnyCodable=[…这里的示例dict…]easierToUse.nested?.array?[2]?.c=“NOT charles”do{let data=try jsonecoder().encode(easierToUse)try data.write(to:fileUrl)}catch let error{print(error)}
如果我不更改它,它会保存罚款。(难道任何编码都不应该是可编码和可解码的吗?)
// 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
}
}
}