Home > Back-end >  How to use the completion handler version of a async function in Swift?
How to use the completion handler version of a async function in Swift?

Time:09-09

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?

CodePudding user response:

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()

CodePudding user response:

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.

  • Related