Coroutine - Avoiding using Suspend function

1.2k Views Asked by At

I am new to KMM and coroutines. Is there a way to await for a response from an async function without needing to make the dependent function also suspend?

Code Example

// In HttpClient.kt in commonMain

class MyHttpClient {
    val client = HttpClient()

    suspend fun get(url: String): String {
        client.get<String>(url)
    }
}

// In Another class in commonMain
class Foo {
    private val httpClient = MyHttpClient()

    fun performAction() { <--- #1
        val data = httpClient.get("server url")
        // So stuff with that data after its retrieve from server.
    }
}

// In iOS swift code
struct Example: View {

    var body: some View {
        Button {
            foo.performAction() <--- #2
        } label: {
            Text("Click Me")
        }
    }

}

if i make #1 a suspend function #2 needs an unnecessary callback. example

// In iOS swift code
struct Example: View {

    var body: some View {
        Button {
            foo.performAction(completionHandler: handler)
        } label: {
            Text("Click Me")
        }
    }

    private func handler(response: KotlinUnit?, error: Error?) {
        // DO NOTHING
    }
}

Also my unit test fail because you cant make test suspend functions and runBlocking isnt in commonMain.

1

There are 1 best solutions below

0
On

You don't need to add that completion callback. All you have to do is launch a coroutine from the click handler, like this:

    Button {
        viewScope.launch {
            foo.performAction()
            // add GUI code here that runs when action is done
        }
    } label: {
        Text("Click Me")
    }

If you don't currently have a coroutine scope defined, you should add it like this (approximately):

struct Example: View {
    private val viewScope = CoroutineScope(Dispatchers.Main)

    // adapt this to the actual way you get the "view closed" event
    fun onClose() { 
        viewScope.cancel()
    ​}

   ​...
}

Dispatchers.Main makes your coroutine run on the GUI thread. Since you are using suspendable IO (as witnessed by your suspend fun get(url: String): String), there is no need to use any other thread.