Swift Async改造delegate
1.背景
Async await的组合是Swift异步编程的核心,它让原本难以读懂的delegate异步过程,变得更加可读。但直接使用Async和await是不够的,我们需要引入withCheckedContinuation{} 这个函数
2.范例
假如我有一个函数,调用以后,它通过delegate异步返回结果。这是一个非常典型的异步函数调用过程。那我们要怎么用Swift的async-await改造它呢?
我们先看看原来长什么样,如下面代码所示,是一个很常见的异步请求回调的过程。
import Foundation
protocol RequestDelegate: AnyObject {
func onLoadedList(_ status: RequestStatus)
}
enum RequestStatus {
case success
case fail
}
class TestDataHanlder {
func fetchListData(_ delegate: RequestDelegate) {
// call a method with delegate
loadListData(delegate)
}
func loadListData(_ delegate: RequestDelegate) {
// do something needs time...
}
}
extension TestDataHanlder: RequestDelegate {
func onLoadedList(_ status: RequestStatus) {
// request done, update UI or something else..
}
}
让我们用async和withCheckedContinuation来改造一下,我们声明了一个CheckedContinuation,把它定义为CheckedContinuation<RequestStatus, Never>,就是告诉系统,返回值是RequestStatus,错误类型是Never。
接着,我们把fetchListData函数改成了async异步函数,在内部,return await withCheckedContinuation,返回值就是loadContinuation的返回值,也就是我们定义好的RequestStatus类型。
最后我们要做的是,是在delegate方法中,调用loadContinuation?.resume(returning: status),并且把delegate返回的status往上抛出。
这样一个delegate的async改造就好了
import Foundation
protocol RequestDelegate: AnyObject {
func onLoadedList(_ status: RequestStatus)
}
enum RequestStatus {
case success
case fail
}
class TestDataHanlder {
typealias TestContinuation = CheckedContinuation<RequestStatus, Never>
private var loadContinuation: TestContinuation?
func fetchListData(_ delegate: RequestDelegate) async -> RequestStatus {
return await withCheckedContinuation { continuation in
loadContinuation = continuation
self.loadListData(delegate)
}
}
func loadListData(_ delegate: RequestDelegate) {
// do something needs time...
}
}
extension TestDataHanlder: RequestDelegate {
func onLoadedList(_ status: RequestStatus) {
loadContinuation?.resume(returning: status)
// !!! WARNING: you must clear the loadContinuation after resume
loadContinuation = nil
}
}
需要注意,当你在异步回调delegate方法里resume之后,要把CheckedContinuation置为nil,否则会有难以预料的结果。
网友评论