iOS 上的 KMM:没有事件循环。使用 runBlocking { ... } 开始一个

KMM on iOS: There is no event loop. Use runBlocking { ... } to start one

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

我正在尝试调用此函数

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。此问题仅存在于 iOSAndroid 完美运行。

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

新的本机并发模型 available for preview. Check out New memory model migration guide。此功能与 Kotlin 1.7.0.

一起发布后,将不再需要下面描述的 native-mt 后缀

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

所以用

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

另请注意,根据 documentation:

When using other libraries that also depend on kotlinx.coroutines, such as Ktor, make sure to specify the multithreaded version of kotlinx-coroutines. You can do this with strictly:

implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt"){
    version {
        strictly("1.5.2-native-mt")
    }
}

您也可以使用常规 coroutines 库,但是您需要创建自定义 CoroutineDispatcher that posts the task on the 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 分支明确指出了切换线程的问题,因此使用它可能仍然是个好主意。否则,您将被限制在一个主线程上。