姬長信(Redy)

Swift5之Result类型

#### 引入 在 iOS 开发中/uff0c经常会有很多时候接收异步回调/uff0c比如网络部分 `URLSession` 的 `dataTask(with:completionHandler:)` 方法/uff0c经常会有如下的代码出现/uff1a ```swift let request = URLRequest(url: URL(string: "https://xxxx")!) URLSession.shared.dataTask(with: request) { data, response, error in if error != nil { //处理错误error } else { //处理数据data } } ``` 这里有三个参数/uff1a`(Data?, URLResponse?, Error?)`/uff0c它们都是可选型/uff0c当请求成功时/uff0c`Data `参数包含 `response` 中的数据/uff0c`Error` 为 `nil`/uff1b当发生错误时/uff0c`Error` 指明具体的错误/uff0c`Data` 为 `nil`。显然 `data` 和 `error` 是互斥的/uff0c不存在 `data` 和 `error` 同时为 `nil` 或者同时非 `nil `的情况/uff0c但是编译器却无法确认这个事实。于是在 Swift 5 中/uff0c新增了一个枚举类型 `Result`/uff0c使我们能够更简单、更清晰地处理复杂代码中的错误。 #### 定义 ```swift public enum Result where Failure: Error { /// A success, storing a `Success` value. case success(Success) /// A failure, storing a `Failure` value. case failure(Failure) ... } ``` - 接收两个泛型参数/uff0c一个为`Success`/uff0c一个为`Failure`/uff0c但是`Failure`必须是`Error`类型的 - `Success`代表正确执行的值 - `Failure`代表出现问题时的错误值 #### 简单案例 ```swift import UIKit // 定义Error enum FileReadError: Error { case FileISNull case FileNotFound } // 用Result处理 func readFileContent(filePath: String) -> Result { // 1.filePath为"" if filePath == "" { return .failure(.FileISNull) } // 2.filepath有值/uff0c但是没有对应的文件 if filePath != "/User/Desktop/123.plist" { return .failure(.FileNotFound) } // 3.取出其中的内容 return .success("123") } //let result = readFileContent(filePath: "") //文件为空 //let result = readFileContent(filePath: "11111") //文件找不到 let result = readFileContent(filePath: "/User/Desktop/123.plist") //123 // 处理Result switch result { case .failure(let error): switch error { case .FileISNull: print("文件为空") case .FileNotFound: print("文件找不到") } case .success(let content): print(content) } ``` #### 错误处理 有没有发现/uff0c有了`Result`/uff0c处理异常有了明显的变化/uff0c显得更简洁 ```swift // swift5 之前的 throw 的异常需要 do try catch 处理 do { handle(try String(contentsOfFile: myFile)) } catch { handleError(error) } ``` ```swift // 有了Reuslt之后 let str = Result { try String(contentsOfFile: myFile) } handle(str) ``` #### 异步失败处理案例 截止目前/uff0c`URLSession`的`dataTask`尚未提供返回`Result`的方法/uff0c只能举个简单的异步回调的案例/uff08实际开发中不会这样处理/uff0c仅仅学习演示之用/uff09 ```swift // 1.定义Error enum NetworkError: Error { case URLInvalid } // 定义一个函数/uff0c包含一个逃逸闭包进行异步回调 func getInfo(from urlString: String, completionHandler: @escaping (Result) -> Void) { if urlString.hasPrefix("https://") { // 经过一系列网络处理以后得到一个服务器返回的数据 let data = "response result" // 获取数据 completionHandler(.success(data)) } else{ // URL有问题 completionHandler(.failure(.URLInvalid)) } } // 调用函数 getInfo(from: "https://www.baidu.com") { result in // 处理Result switch result { case .success(let content): print(content) case .failure: // 如果参数不是https://开头 会打印 print("url有问题") } } ``` #### 优点 - 使用 `Result `类型处理异步失败变得更加自然优雅 - 处理 `Result `时很简单/uff0c要么得到错误/uff0c要么得到正确的值 - 限制返回的错误类型/uff0c这个错误也是一个枚举