Mapping Dictionary keys

该图片由Markus SpiskePixabay上发布

问题

OCSwift 混编赋值函数参数时,出现类型不匹配的问题:

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.KeyNSNotification.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}

参考

swift.org

Loading Disqus comments...
Table of Contents