内容简介:在异步获取数据的场景中,常见的回调的数据结构是这样的:表示获取成功的数据,表示获取失败的 error。因为数据可能获取成功,也可能失败。因此回调中的数据和错误都是 optional 类型。 比如 CloudKit 中保存数据的一个函数就是这样:这种形式的缺点是没有体现出两种结果的互斥关系:如果数据成功获取到了,那么 error 一定为空。如果 error 有值,数据一定是获取失败了。Swift 中枚举的能力相比 OC 有着很大的进步,每个枚举值除了可以是常规的基础类型,还可以是一个关联的类型。有了这样的特性
在异步获取数据的场景中,常见的回调的数据结构是这样的:表示获取成功的数据,表示获取失败的 error。因为数据可能获取成功,也可能失败。因此回调中的数据和错误都是 optional 类型。 比如 CloudKit 中保存数据的一个函数就是这样:
func save(_ record: CKRecord, completionHandler: @escaping (CKRecord?, Error?) -> Void) 复制代码
这种形式的缺点是没有体现出两种结果的互斥关系:如果数据成功获取到了,那么 error 一定为空。如果 error 有值,数据一定是获取失败了。
Swift 中枚举的能力相比 OC 有着很大的进步,每个枚举值除了可以是常规的基础类型,还可以是一个关联的类型。有了这样的特性后用枚举来优化返回结果的数据结构显得水到渠成:
enum Result<Success, Failure> where Failure : Error { /// A success, storing a `Success` value. case success(Success) /// A failure, storing a `Failure` value. case failure(Failure) } 复制代码
基本用法
定义异步返回结果是 Int 类型的函数:
func fetchData(_ completionHandler: @escaping (Result<Int, Error>) -> Void) { DispatchQueue.global().async { let isSuccess = true if isSuccess { let resultValue = 6 return completionHandler(.success(resultValue)) } else { let error = NSError(domain: "custom error", code: -1, userInfo: nil) return completionHandler(.failure(error)) } } } 复制代码
返回值的类型通过泛型进行约束, Result
第一个泛型类型表示返回值的类型,第二个类型表示错误的类型。对 Result
赋值和常规的枚举一样:
let valueResult: Result<Int, CustomError> = Result.success(4) // 因为 swift 中会进行类型推断,编译器在确认返回的是 `Result` 类型后,可以省略枚举类型的声明 let errorResult = .failure(CustomError.inputNotValid) 复制代码
取出 Result
值和获取普通的关联类型枚举是一样的:
fetchData { (result) in switch result { case .success(let value): print(value) case .failure(let error) print(error.localizedDescription) } } 复制代码
如果你只想要获取其中一项的值,也可以直接用 if case 拆包:
fetchDate { (result) in if case .success(let value) = result { print(value) } } 复制代码
可以判等
Enum 是一个值类型,是一个值就应该可以判断是否相等。如果 Result
的成功和失败的类型都是 Equatable
,那么 Result
就可以判等,源码如下:
extension Result : Equatable where Success : Equatable, Failure : Equatable { } 复制代码
类似的,如果是成功和失败的类型都是 Hashable
,那么 Result
也是 Hashable
:
extension Result : Hashable where Success : Hashable, Failure : Hashable { } 复制代码
如果实现了 Hashable
,可以用来当做字典的 key。
辅助的 API
map、mapError
与 Dictionary 类似,Swift 为 Result
提供了几个 map value 和 error 的方法。
let intResult: Result<Int, Error> = Result.success(4) let stringResult = x.map { (value) -> Result<String, Error> in return .success("map") } let originError = NSError(domain: "origin error", code: -1, userInfo: nil) let errorResult: Result<Int, Error> = .failure(originError) let newErrorResult = errorResult.mapError { (error) -> Error in let newError = NSError(domain: "new error", code: -2, userInfo: nil) return newError } 复制代码
flatMap、flatMapError
map 返回的是具体的结果和错误, flatMap 闭包中返回的是 Result
类型。如果 Result
中包含的是数据,效果和 map 一致,替换数据;如果 Result
中包含的是错误,那么不替换结果。
let intResult: Result<Int, Error> = Result.success(4) // 替换成功 let flatMapResult = intResult.flatMap { (value) -> Result<String, Error> in return .success("flatMap") } // 没有执行替换操作,flatMapIntResult 值还是 intResult let flatMapIntResult = intResult.flatMap { (value) -> Result<String, Error> in return .failure(NSError(domain: "origin error", code: -1, userInfo: nil)) } 复制代码
get
很多时候只关心 Result
的值,Swift 提供了 get()
函数来便捷的直接获取值,需要注意的是这个函数被标记为 throws
,使用时语句前需要加上 try
:
let intResult: Result<Int, Error> = Result.success(4) let value = try? intResult.get() 复制代码
可抛出异常的闭包初始化器
很多时候获取返回值的闭包中可能会发生异常代表获取失败的错误,基于这个场景 Swift 提供了一个可抛出异常的闭包初始化器:
enum CustomError: Error, Equatable { case inputNotValid } let fetchInt = { () -> Int in if true { return 4 } else { throw CustomError.inputNotValid } } let result: Result<Int, Error> = Result { try fetchInt() } 复制代码
需要提醒是通过这种方式声明的 Result
的 error 类型只能是 Error
,不能指定特定的 Error
。
-
微博:(weibo.com/1926303682)
-
如果想与我有更密切的交流也可以加入我的知识星球:( t.zsxq.com/JEiqj27 )
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Swift 5.0 值得关注的特性:增加 Result 枚举类型
- c# – 枚举时项目发生变化时是否会影响枚举?
- 测者的测试技术手册:Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)
- 测者的JUnit单元测试探坑记:Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)
- c# – 循环枚举类型
- Python 的枚举类型
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。