KMM на iOS: нет цикла событий. Используйте runBlocking {…}, чтобы запустить его

Я пытаюсь использовать в Kotlin Multiplatformпроект. Я ни в чем не разбираюсь.

Я пытаюсь вызвать эту функцию

      fun startFlow {
    coroutineScope.launch { 
        withContext(defaultDispatcher) {
           myFlow.collect { next -> onNext(next) }
        } 
    }
}

coroutineScope на этом

      val defaultScope: CoroutineScope = object : CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = SupervisorJob() + Dispatchers.Default
}

Это не единственный вызов, который вызывает у меня эту проблему, фактически все обращения к coroutines похоже, не работает с этой ошибкой:

      kotlin.IllegalStateException: There is no event loop. Use runBlocking { ... } to start one.

Вот как я импортирую библиотеку

      val commonMain by getting {
        dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3")
        }
    }

я использую Kotlin1.4.31. Эта проблема присутствует только в iOS, Android работает безупречно.

Я не понимаю, упускаю ли я что-то.

3 ответа

для iOS вам необходимо использовать сопрограммы с суффиксом "native-mt", подробнее здесь

поэтому замените свой импорт на

      implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3-native-mt")

Если вы используете последнюю версию KMM, и указанная выше библиотека native-mt не работает, то вот решение для вас:

  1. Перейти к вашейgradle.properties

  2. В#kotlinразделе (или на новой строке) добавьте следующую строку

    kotlin.native.binary.memoryModel=experimental

  3. Синхронизируйте файлы Gradle

Это должно включить экспериментальную модель памяти для Kotlin, и ваш проект должен начать работать на iOS.

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

      object NSLooperDispatcher: CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        NSRunLoop.mainRunLoop.performBlock {
            block.run()
        }
    }
}

// use custom dispatcher
withContext(NSLooperDispatcher) {
    myFlow.collect { next -> onNext(next) }
} 

Есть проблемы с переключением потоков, которые native-mtветвь сопрограмм подробно описана, поэтому ее использование может быть хорошей идеей. В противном случае вы ограничены одним основным потоком.

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