Coroutine - отказ от использования функции приостановки

Я новичок в KMM и сопрограммах. Есть ли способ дождаться ответа от асинхронной функции, не заставляя зависимую функцию также приостанавливаться?

Пример кода

      // 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")
        }
    }

}

если я делаю № 1, то функция приостановки № 2 требует ненужного обратного вызова. пример

      // 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
    }
}

Также мой модульный тест не работает, потому что вы не можете сделать тестовые функции приостановки и runBlocking нет общего

2 ответа

Вам нужно указать сопрограмму, на которой должен запускаться ваш метод.

      fun performAction() { <--- #1
    CoroutineScope(Dispatchers.Default).launch {
        val data = httpClient.get("server url")
        // So stuff with that data after its retrieve from server.
        MainScope().launch {
            // if you need to update UI from the main thread, call it here
        }
    }
}

Вам не нужно добавлять этот обратный вызов завершения. Все, что вам нужно сделать, это запустить сопрограмму из обработчика кликов, например:

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

Если у вас в настоящее время не определена область сопрограммы, вы должны добавить ее примерно так:

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

   ​...
}

Это заставляет вашу сопрограмму работать в потоке графического интерфейса. Поскольку вы используете приостанавливаемый ввод-вывод (что подтверждается вашим suspend fun get(url: String): String), нет необходимости использовать какой-либо другой поток.

Другие вопросы по тегам