繁体   English   中英

如何在 Swift 的异步闭包内捕获局部变量?

[英]How to capture local variable inside an async closure in Swift?

我在 Swift 5.5 和 iOS 15 中有以下代码

func getReviewIds() {
    
    var reviewIds: [Int] = []
    
    Task {
        let ids = await getReviewIdsFromGoogle()
        reviewIds.append(contentsOf: ids)
    }
    
    print("outside")
}

func getReviewIdsFromGoogle() async -> [Int] {
    await withUnsafeContinuation { continuation in
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
            continuation.resume(returning: [1,2,3])
        }
    }
}

我在以下行的getReviewIdsFromGoogle function 中收到错误:

 reviewIds.append(contentsOf: ids)

Mutation of captured var 'reviewIds' in concurrently-executing code

我知道我可以将getReviewIdsFromGoogle async function 而不是使用async闭包,但是如何使用闭包解决这个问题。

为了防止数据竞争,您必须使用同步访问来自并发操作的变量,并且编译器不允许您直接更改数组。 为避免该问题,您可以使用actor实例实现对数据的隔离访问,例如:

actor Store {
    var reviewIds: [Int] = []
    func append(ids: [Int]) {
        reviewIds.append(contentsOf: ids)
    }
}

func getReviewIds() {
    
    let store = Store()
    
    Task {
        let ids = await getReviewIdsFromGoogle()
        await store.append(ids: ids)
        print(await store.reviewIds)
    }
}

一旦启动了异步上下文,就无法将数据传回原始同步上下文,因为这将要求原始上下文在等待异步结果时“阻塞”。 Swift 不允许在其并发 model 中阻塞,因为这可能导致线程死锁。

您只需使用来自Task上下文的结果调用另一个 function 来处理返回的值。 这个过程是否是另一个async function 取决于您,这取决于您需要做什么。

func getReviewIDs() {
    Task {
        let result = await getReviewIdsFromGoogle()
        process(ids: result)
    }
}

func process(ids: [Int]) {
    print("now process ids: \(ids)")
}

func getReviewIdsFromGoogle() async -> [Int] {
    await withUnsafeContinuation { continuation in
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
            continuation.resume(returning: [1,2,3])
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM