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

Mar*_*Doe 31 async-await 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])
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

getReviewIdsFromGoogle我在以下行中收到函数错误:

reviewIds.append(contentsOf: ids)
Run Code Online (Sandbox Code Playgroud)

并发执行代码中捕获的 var 'reviewIds' 的突变

我知道我可以创建getReviewIdsFromGoogle一个async函数而不是使用async闭包,但是如何使用闭包解决这个问题。

iUr*_*rii 20

为了防止数据竞争,您必须使用并发操作对变量的同步访问,并且编译器不允许您直接更改数组。为了避免这个问题,您可以使用实例实现对数据的隔离访问,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)
    }
}
Run Code Online (Sandbox Code Playgroud)


Bra*_*key 11

一旦启动异步上下文(例如创建新的Task),您就无法将数据传递回原始同步上下文,因为这将要求原始上下文在等待异步结果时“阻塞”。Swift 不允许在其并发模型中阻塞,因为这可能会导致线程死锁。每个线程都需要能够“前进”。

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

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])
        }
    }
}
Run Code Online (Sandbox Code Playgroud)