Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have the following code in Swift 5.5 and 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])
        }
    }
}

I get an error in getReviewIdsFromGoogle function on the following line:

reviewIds.append(contentsOf: ids)

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

I know that I can make the getReviewIdsFromGoogle an async function instead of using the async closure, but how can I solve this using the closure.

like image 976
Mary Doe Avatar asked Sep 04 '25 01:09

Mary Doe


1 Answers

To prevent data races you must use synchronized access to variables from concurrent operations and the compiler doesn't allow you to change your array directly. To avoid the issue you can implement isolated access to your data with an actor instance e.g.:

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)
    }
}
like image 105
iUrii Avatar answered Sep 07 '25 19:09

iUrii