A sample of coroutines dispatcher with delay support for an iOS application.
In case of use ktor as http client you can ignore SSL errors for development environment in the following way:
Example
Shared
import kotlinx.coroutines.CoroutineDispatcher
expect val backgroundDispatcher: CoroutineDispatcher
expect val mainDispatcher: CoroutineDispatcher
Android
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
actual val backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO
actual val mainDispatcher: CoroutineDispatcher = Dispatchers.Main
iOS
actual val backgroundDispatcher: CoroutineDispatcher =
NsQueueDispatcher(dispatch_get_main_queue())
actual val mainDispatcher: CoroutineDispatcher =
NsQueueDispatcher(dispatch_get_main_queue())
NsQueueDispatcher.kt
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Delay
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.Runnable
import platform.darwin.DISPATCH_TIME_NOW
import platform.darwin.dispatch_after
import platform.darwin.dispatch_async
import platform.darwin.dispatch_get_main_queue
import platform.darwin.dispatch_queue_t
import platform.darwin.dispatch_time
import kotlin.coroutines.CoroutineContext
@OptIn(InternalCoroutinesApi::class)
internal class NsQueueDispatcher(
private val dispatchQueue: dispatch_queue_t
) : CoroutineDispatcher(), Delay {
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatch_async(dispatchQueue) {
block.run()
}
}
@InternalCoroutinesApi
@Suppress("TooGenericExceptionCaught")
override fun scheduleResumeAfterDelay(
timeMillis: Long,
continuation: CancellableContinuation<Unit>
) {
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, timeMillis * NANOSECONDS_IN_MILLIS),
dispatch_get_main_queue()
) {
try {
with(continuation) {
resumeUndispatched(Unit)
}
} catch (err: Throwable) {
println("scheduleResumeAfterDelay ${err.stackTraceToString()}")
throw err
}
}
}
@InternalCoroutinesApi
@Suppress("TooGenericExceptionCaught")
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 * NANOSECONDS_IN_MILLIS),
dispatch_get_main_queue()
) {
try {
if (!handle.disposed) {
block.run()
}
} catch (err: Throwable) {
println("invokeOnTimeout ${err.stackTraceToString()}")
throw err
}
}
return handle
}
companion object {
private const val NANOSECONDS_IN_MILLIS = 1_000_000
}
}
Usage
GlobalScope.launch(backgroundDispatcher) {
println("step 1")
delay(5000)
println("step 2")
}
Result
Now you can use function delay() in the iOS application.