Mapping Dictionary keys
该图片由Markus Spiske在Pixabay上发布
问题
在 OC
和 Swift
混编赋值函数参数时,出现类型不匹配的问题:
OC
中的方法:
+ (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options;
其中options
的类型为 NSDictionary<NSString*, id>
;
桥接到 Swift
中时,options
的类型为 [String: Any]
。
Swift
中的方法:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
其中 options
的类型为 [UIApplication.OpenURLOptionsKey : Any]
因为 swift
是强类型语言,因此无法直接把 [UIApplication.OpenURLOptionsKey : Any]
类型的值赋给 [String: Any]
类型
类型不一致时赋值,编译器会报错
解决
需要把 [UIApplication.OpenURLOptionsKey : Any]
类型 转化为 [String: Any]
类型
UIApplication.OpenURLOptionsKey
遵循了 RawRepresentable
协议,所以通过 key.rawValue
即可转换为 String
类型
简单粗暴的方式 for in
var transOptions = [String: Any]()
for x in options {
transOptions[x.key.rawValue] = x.value
}
呃。。。不够优雅,使用 reduce
函数简化
let transOptions = options.reduce(into: [:]) { (result, x) in
result[x.key.rawValue] = x.value
}
呃。。。不够通用,遇到 NSAttributedString.Key
、NSNotification.Name
等类型 或者 [Int: Any]
转换 [String: Any]
等 key
需要转换的时候,需要写重复代码。
泛型封装
extension Dictionary {
func compactMapKeys<T>(_ transform: ((Key) throws -> T?)) rethrows -> Dictionary<T, Value> {
return try self.reduce(into: [T: Value](), { (result, x) in
if let key = try transform(x.key) {
result[key] = x.value
}
})
}
}
使用方式如下
let transOptions = options.compactMapKeys {$0.rawValue}