简体   繁体   中英

How to use the completion handler version of a async function in Swift?

I have a async function func doWork(id: String) async throws -> String . I want to call this function from a concurrent dispatch queue like this to test some things.

for i in 1...100 {
    queue.async {
        obj.doWork(id: "foo") { result, error in 
          ...
        }
    }
}

I want to do this because queue.async { try await obj.doWork() } is not supported. I get an error:

Cannot pass function of type '@Sendable () async throws -> Void' to parameter expecting synchronous function type

But the compiler does not provide me with a completion handler version of doWork(id:) . When I call it from Obj C, I am able to use the completion handler version: [obj doWorkWithId: @"foo" completionHandler:^(NSString * val, NSError * _Nullable error) {... }]

How do I do something similar in Swift?

You can define a DispatchQueue. This DispatchQueue will wait for the previous task to complete before proceeding to the next.

let queue = DispatchQueue(label: "queue")

func doWork(id: String) async -> String {
    print("Do id \(id)")
    return id
}

func doWorksConcurrently() {
    for i in 0...100 {
        queue.async {
            Task.init {
                await doWork(id: String(i))
            }
        }
    }
}

doWorksConcurrently()

You are initiating an asynchronous task and immediately finishing the dispatch without waiting for doWork to finish. Thus the dispatch queue is redundant. One could do:

for i in 1...100 {
    Task {
        let results = try await obj.doWork(id: "foo")
        ...
    }
}

Or, if you wanted to catch/display the errors:

for i in 1...100 {
    Task {
        do {
            let results = try await obj.doWork(id: "foo")
            ...
        } catch {
            print(error)
            throw error
        }
    }
}

Now, generally in Swift, we would want to remain within structured concurrency and use a task group. But if you are trying to mirror what you'll experience from Objective-C, the above should be sufficient.

Needless to say, if your Objective-C code is creating a queue solely for the purpose for calling the completion-handler rendition of doWork , then the queue is unnecessary there, too. But we cannot comment on that code without seeing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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