Update: It works if I first execute a coroutine without timeout and then withTimeout. But If I execute a coroutine withTimeout first then it gives me an error. same goes for Async as well.
I am creating a demo kotlin multiplatform application where I am executing an API call with ktor. I want to have a configurable timeout function on ktor request so I am using withTimeout at coroutine level.
Here is my function call with network 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
}
Here is my AppDispatcher class for the iOSMain module.
@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()
}
}
}
}
so the function with the timeout gives me the following error in iOS client.
kotlin.IllegalStateException: There is no event loop. Use runBlocking { ... } to start one.
I am using 1.3.2-native-mt-1 version of the kotlin-coroutine-native. I have created a sample demo application at the following URL. https://github.com/dudhatparesh/kotlin-multiplat-platform-example
So, as mentioned in comment above I had similar issue but turned out that it wasn't picking up the native-mt
version due to transitive dependencies in other libraries. Added following and it's resolving now.
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core-native')
{
version {
strictly '1.3.3-native-mt'
}
}
Also note guidance in https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md
Starting to make use of this in https://github.com/joreilly/PeopleInSpace
If you want to use [withTimeout]
functions in coroutines you have to modify your Dispatcher
to implement Delay
interface. Here is an example of how this can be achieved:
@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
}
}
This solution can be easily modified for your needs.
More information can be found in this thread.
UPDATE
At the moment there is a version 1.3.9-native-mt
of kotlinx:kotlinx-coroutines-core
artifact which gives the ability to use Dispatchers.Main
on ios platform (it supports delay
out of the box). It even supports Dispatchers.Default
which is used for background work. You can read docs in native-mt branch. Worth noting that the version for ios should be set strictly:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt") {
version {
strictly('1.3.9-native-mt')
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With