Reputation: 21
Currently I call myFunction
as such:
myFunction() { list in
// do whatever with list
}
I would like to be able to call it like this:
let list = await myFunction()
// do whatever with list
So from what I understand I need to convert myFunction
to be async. Currently it looks like:
func myFunction(currentList: [String] = [], startIndex: Int = 0, completion: @escaping ([String]) -> Void) {
var list = currentList
let maxSize = 10
let endIndex = start + maxSize - 1
privateFunction(range: startIndex...endIndex) { items in
list.append(items)
if items.count < maxSize {
completion(list)
} else {
myFunction(currentList: list, startIndex: startIndex + maxSize, completion: completion)
}
}
}
However, myFunction
calls a private function that I do not have access to so cannot modify. I learned that a way to deal with this is to use withCheckedContinuation
. So I modify myFunction
to look like this:
func myFunction(currentList: [String] = [], startIndex: Int = 0) async -> [String] {
var list = currentList
let maxSize = 10
let endIndex = start + maxSize - 1
return await withCheckedContinuation { continuation in
privateFunction(range: startIndex...endIndex) { items in
list.append(items)
if items.count < maxSize {
continuation.resume(returning: list)
} else {
// ???
}
}
}
}
I'm not sure what to put in the commented area above, since when that part of the code is reached, the function is to call itself unless the condition is met.
Upvotes: 2
Views: 186
Reputation: 1480
I had this exact same problem and was in search of a solution. Rob's answer works in most cases and you should use it if async-await syntax is available on the private function. However in case you do not have access to the privateFunction
as in case of OP, recursion is not avoidable(unless someone proves otherwise).
Since privateFunction
needs a sync closure, just call myFunction
inside a Task. This is how I made it work in playground
func privateFunction(range: ClosedRange<Int>, completion: @escaping ([String]) -> Void) {
let items = (range.lowerBound...range.upperBound).filter { $0 < 100 }.map { "Item \($0)" }
completion(items)
}
func myFunction(startIndex: Int = 0) async -> [String] {
let maxSize = 10
let endIndex = startIndex + maxSize - 1
return await withCheckedContinuation { continuation in
privateFunction(range: startIndex...endIndex) { items in
if items.count < maxSize {
continuation.resume(returning: items)
} else {
Task {
let nextList = await myFunction(startIndex: startIndex + maxSize)
continuation.resume(returning: items + nextList)
}
}
}
}
}
Task {
await myFunction()
.map { print($0) }
}
Upvotes: 0
Reputation: 437382
With async-await, the recursion is no longer necessary.
First, you would make an asynchronous rendition of your private function, e.g.
func privateFunction(range: ClosedRange<Int>) async -> [String] {
await withCheckedContinuation { continuation in
privateFunction(range: range) { items in
continuation.resume(returning: items)
}
}
}
And then, myFunction
is reduced to a simple loop:
func myFunction() async -> [String] {
var results: [String] = []
var items: [String]
let maxSize = 10
var startIndex = 0
repeat {
let endIndex = startIndex + maxSize - 1
items = await privateFunction(range: startIndex...endIndex)
results += items
startIndex += maxSize
} while items.count >= maxSize
return results
}
Upvotes: 2
Reputation: 1834
Try using this async implementiation of myFuntion
:
@available(iOS 15.0,tvOS 15.0, macOS 12.0, *)
public func myFunction(currentList: [String] = [], startIndex: Int = 0) async throws -> [String] {
return try await withCheckedThrowingContinuation { continuation in
self.myFunction(currentList: currentList, startIndex: startIndex) { result in
continuation.resume(returning: result)
}
}
}
Upvotes: 1