![](/img/trans.png)
[英]Kotlin Multiplatform use NSUserDefaults setValue String on iOS got error
[英]withTimeout function gives IllegalStateException: There is no event loop. Use runBlocking { ... } to start one. in Kotlin Multiplatform iOS client
更新:如果我首先在没有超时的情况下执行协程然后使用超时,它会起作用。 但是如果我先执行一个协程 withTimeout 那么它会给我一个错误。 异步也是如此。
我正在创建一个演示 kotlin 多平台应用程序,我在其中使用 ktor 执行 API 调用。 我想在 ktor 请求上有一个可配置的超时功能,所以我在协程级别使用 withTimeout 。
这是我使用网络 API 调用的函数。
suspend fun <T> onNetworkWithTimeOut(
url: String,
timeoutInMillis: Long,
block: suspend CoroutineScope.() -> Any): T {
return withTimeout(timeoutInMillis) {
withContext(dispatchers.io, block)
} as T
}
suspend fun <T> onNetworkWithoutTimeOut(url: String, block: suspend CoroutineScope.() -> Any): T {
return withContext(dispatchers.io, block) as T
}
这是我的 iOSMain 模块的 AppDispatcher 类。
@InternalCoroutinesApi
actual class AppDispatchersImpl : AppDispatchers {
@SharedImmutable
override val main: CoroutineDispatcher =
NsQueueDispatcher(dispatch_get_main_queue())
@SharedImmutable
override val io: CoroutineDispatcher =
NsQueueDispatcher(dispatch_get_main_queue())
internal class NsQueueDispatcher(
@SharedImmutable private val dispatchQueue: dispatch_queue_t
) : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.mainRunLoop().performBlock {
block.run()
}
}
}
}
所以带有超时的函数在 iOS 客户端中给了我以下错误。
kotlin.IllegalStateException: There is no event loop. Use runBlocking { ... } to start one.
我正在使用 kotlin-coroutine-native 的 1.3.2-native-mt-1 版本。 我在以下 URL 创建了一个示例演示应用程序。 https://github.com/dudhatparesh/kotlin-multiplat-platform-example
所以,正如上面评论中提到的,我有类似的问题,但结果是由于其他库中的传递依赖关系,它没有选择native-mt
版本。 添加了以下内容,现在正在解决。
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core-native')
{
version {
strictly '1.3.3-native-mt'
}
}
另请注意https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md 中的指导
如果你想在协程中使用[withTimeout]
函数,你必须修改你的Dispatcher
来实现Delay
接口。 以下是如何实现这一目标的示例:
@UseExperimental(InternalCoroutinesApi::class)
class UI : CoroutineDispatcher(), Delay {
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatch_async(dispatch_get_main_queue()) {
try {
block.run()
} catch (err: Throwable) {
throw err
}
}
}
@InternalCoroutinesApi
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeMillis * 1_000_000), dispatch_get_main_queue()) {
try {
with(continuation) {
resumeUndispatched(Unit)
}
} catch (err: Throwable) {
throw err
}
}
}
@InternalCoroutinesApi
override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
val handle = object : DisposableHandle {
var disposed = false
private set
override fun dispose() {
disposed = true
}
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeMillis * 1_000_000), dispatch_get_main_queue()) {
try {
if (!handle.disposed) {
block.run()
}
} catch (err: Throwable) {
throw err
}
}
return handle
}
}
可以根据您的需要轻松修改此解决方案。
可以在此线程中找到更多信息。
更新
目前有一个kotlinx:kotlinx-coroutines-core
artifact 的1.3.9-native-mt
版本,它提供了在 ios 平台上使用Dispatchers.Main
的能力(它支持开箱即用的delay
)。 它甚至支持用于后台工作的Dispatchers.Default
。 您可以在 native-mt 分支中阅读文档。 值得注意的是,ios的版本应该严格设置:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt") {
version {
strictly('1.3.9-native-mt')
}
}
有时 ios 应用程序与 android 应用程序有不同的异步要求。 使用此代码解决临时调度问题
object MainLoopDispatcher: CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.mainRunLoop().performBlock {
block.run()
}
}
}
这个问题请看论坛: https : //github.com/Kotlin/kotlinx.coroutines/issues/470
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.