Swift 用async改造delegate

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,否则一旦调用两次resume,会崩溃。如果你的delegate方法会多次回调,则不适合直接用withCheckedContinuation续体。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容