Search code examples
iosswiftasync-awaitconcurrencyswift-concurrency

Swift concurrency. How to rethrow in catch block? Also about recursion in async/await


First of all I have a function for get version from API.

func getVersionAsync() async throws -> VersionEntity {
    return try await withCheckedThrowingContinuation { continuation in
        versionTask.getVersion { result in
            switch result {
            case .success(let response):
                continuation.resume(returning: response.item)
            case .failure(let error):
                continuation.resume(throwing: error)
            }
        }
    }
}

Then I need to handle it or repeat request after 5 seconds:

func checkVersion() async {
    do {
        let versionEntity = try await getVersionAsync()
        // handle versionEntity
    } catch {
        try await Task.sleep(nanoseconds: 5) <- Errors thrown from here are not handled
        await checkVersion()
    }
}

There is an error Errors thrown from here are not handled. What is the correct way to do this in swift concurrency?


Solution

  • I would add throws to the function signature so that the function exits if the sleep call throws an error. This for instance means that the functions exits if the surrounding Task is cancelled.

    func checkVersion() async throws {
        do {
            let versionEntity = try await getVersionAsync()
            // handle versionEntity
        } catch {
            try await Task.sleep(for: .seconds(5))
            try await checkVersion()
        }
    }
    

    Note that I changed the sleep to 5 seconds as that was the time given in the text.

    If you don't want to use recursion then you could wrap the do/catch in a while loop. Here I also added a max tries parameter

    func checkVersion(maxRetries: Int) async throws {
        var allDone = false
        var counter = 0
    
        while allDone == false {
            do {
                counter += 1
                let versionEntity = try await getVersionAsync()
                // handle versionEntity
                allDone = true
            } catch {
                if counter > maxRetries { return } // or maybe throw an error
                try await Task.sleep(for: .seconds(5))
            }
        }
    }