Home > Back-end >  How would I convert a completion hander function to async when recursion is involved?
How would I convert a completion hander function to async when recursion is involved?

Time:07-25

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.

CodePudding user response:

With async-await, the recursion is completely unnecessary.

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 {
        items = await privateFunction(range: startIndex...startIndex   maxSize - 1)
        results  = items
        startIndex  = maxSize
    } while items.count >= maxSize 
    
    return results
}

CodePudding user response:

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)
        }
    }
}
  • Related