异步
异步在 iOS 里是一个常见的操作,例如要在网络请求后更新数据模型和视图。
但是当异步操作嵌套时,不仅容易出现逻辑错误,还可能会陷入回调地狱
先看下下面这段代码
func fetchThumbnail(for id: String, completion: @escaping (Result<UIImage, Error>) -> Void) {
let request = thumbnailURLRequest(for: id)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
} else if (response as? HTTPURLResponse)?.statusCode != 200 {
completion(.failure(FetchError.badID))
} else {
guard let image = UIImage(data: data!) else {
completion(.failure(FetchError.badImage))
return
}
image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
guard let thumbnail = thumbnail else {
completion(.failure(FetchError.badImage))
return
}
completion(.success(thumbnail))
}
}
}
task.resume()
}
为了处理这些异步函数的结果,需要使用 completion 来通知调用方
使用 async 和 await 重构函数
func fetchThumbnail(for id: String) async throws -> UIImage {
let request = thumbnailURLRequest(for: id)
let (data, response) = try await URLSession.shared.data(for: request)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw FetchError.badID }
let maybeImage = UIImage(data: data)
guard let thumbnail = await maybeImage?.thumbnail else { throw FetchError.badImage }
return thumbnail
}
步骤非常简单:
- 生成 request 请求,这是一个同步操作;
- 请求数据,try 标记可能抛出错误,await 标记潜在暂停点,这是一个异步操作;
- 判断返回状态码是否 200,不是则抛出错误;
- 生成原始图片,这是一个同步操作;
- 生成缩略图,await 标记潜在暂停点,无法生成则抛出错误,这是一个异步操作;
- 返回成功生成的缩略图。
网友评论