iOS 上的 KMM:没有事件循环使用 runBlocking { ... } 启动一个

问题描述

我正在尝试在 coroutines 项目中使用 Kotlin Multiplatform。我在这方面都没有经验。

我正在尝试调用函数

fun startFlow {
    coroutinescope.launch { 
        withContext(defaultdispatcher) {
           myFlow.collect { next -> onNext(next) }
        } 
    }
}
coroutinescope 上的

iOS 是这个

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

我使用的是 Kotlin 1.4.31。此问题仅在 iOS 中存在,Android 可以完美运行。

我不明白我是否遗漏了什么。

解决方法

对于 iOS,您需要使用后缀为“native-mt”的协程,更多信息 here

所以用

替换你的导入
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3-native-mt")
,

您也可以使用常规的 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 分支明确指出的切换线程存在问题,因此使用它可能仍然是一个好主意。否则,您将被限制在一个主线程上。