Mat*_*lak 7 ios flatmap swift swift4
我有一个非常基本和直接的对象映射到字典.我在顶层使用和解析字典.其中一个字段是一系列其他字典.设置它们我使用的flatMap似乎是一个合适的方法,但由于里面的对象不可为空,这个方法突然返回元组(至少看起来像这样)而不是字典.
我创建了一个最小的例子,几乎可以在任何执行任何地方粘贴到新项目中,这应该提供更好的细节,然后是任何描述:
func testFlatMap() -> Data? {
class MyObject {
let a: String
let b: Int
init(a: String, b: Int) { self.a = a; self.b = b }
func dictionary() -> [String: Any] {
var dictionary: [String: Any] = [String: Any]()
dictionary["a"] = a
dictionary["b"] = b
return dictionary
}
}
let objects: [MyObject] = [
MyObject(a: "first", b: 1),
MyObject(a: "second", b: 2),
MyObject(a: "third", b: 3)
]
var dictionary: [String: Any] = [String: Any]()
dictionary["objects"] = objects.flatMap { $0.dictionary() }
dictionary["objects2"] = objects.map { $0.dictionary() }
print("Type of first array: " + String(describing: type(of: dictionary["objects"]!)))
print("Type of first element: " + String(describing: type(of: (dictionary["objects"] as! [Any]).first!)))
print("Type of second array: " + String(describing: type(of: dictionary["objects2"]!)))
print("Type of second element: " + String(describing: type(of: (dictionary["objects2"] as! [Any]).first!)))
return try? JSONSerialization.data(withJSONObject: dictionary, options: [])
}
_ = testFlatMap()
Run Code Online (Sandbox Code Playgroud)
所以这段代码崩溃了
'NSInvalidArgumentException',原因:'JSON写入的无效类型(_SwiftValue)'
(使用do-catch没有区别,这是第一个WTH,但现在让我们离开)
那么让我们看一下日志所说的内容:
Type of first array: Array<(key: String, value: Any)>
Type of first element: (key: String, value: Any)
Type of second array: Array<Dictionary<String, Any>>
Type of second element: Dictionary<String, Any>
Run Code Online (Sandbox Code Playgroud)
第二个是我们所期望的,但第一个只是在那里有元组.这是自然的,故意的吗?
你全力以赴之前,"为什么使用flatMap非可选值"让我来解释一下,func dictionary() -> [String: Any]以前是func dictionary() -> [String: Any]?因为它已跳过缺少一些数据项.
因此,只有?在该方法结束时添加少量才会将输出更改为:
Type of first array: Array<Dictionary<String, Any>>
Type of first element: Dictionary<String, Any>
Type of second array: Array<Optional<Dictionary<String, Any>>>
Type of second element: Optional<Dictionary<String, Any>>
Run Code Online (Sandbox Code Playgroud)
这意味着第一个解决方案是正确的解决方案.在变化时,没有任何警告,也没有任何警告.该应用程序将突然开始崩溃.
最后的问题显然是"如何避免这种情况?" 没有太多工作.使用dictionary["objects"] = objects.flatMap { $0.dictionary() } as [[String: Any]]似乎可以做到保留单线的技巧.但使用它似乎非常愚蠢.
我看到你的问题归结为mapvs. flatMap。map是更一致的一个,它在这里按预期工作,所以我不会深入研究它。
现在:您的问题是提出SE-0187flatMap的原因之一。有 3 个重载:flatMap
Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element] where S : Sequence
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]
Run Code Online (Sandbox Code Playgroud)
当您的dictionary()函数返回非可选值时,它会使用第一个重载。由于字典是键值元组的序列,因此您得到的是元组数组。
当你的dictionary()函数返回一个可选值时,它使用第三个重载,它本质上过滤掉了nils。这种情况可能会非常混乱,因此建议(并接受)SE-0187compactMap将此重载重命名为.
从 Swift 4.1(Xcode 9.3,目前处于测试版)开始,您可以使用compactMap:
// Assuming dictionary() returns [String: Any]?
dictionary["objects"] = objects.compactMap { $0.dictionary() }
Run Code Online (Sandbox Code Playgroud)
对于 Swift < 4.1,您提供的解决方案是唯一有效的解决方案,因为它为编译器提供了使用第三个重载的提示:
dictionary["objects"] = objects.flatMap { $0.dictionary() } as [[String: Any]]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1669 次 |
| 最近记录: |