업데이트 : 시간 초과없이 코 루틴을 먼저 실행 한 다음 시간 초과로 작동하면 작동합니다. 그러나 먼저 timeout with coroutine을 실행하면 오류가 발생합니다. Async도 마찬가지입니다.
ktor로 API 호출을 실행하는 데모 kotlin 멀티 플랫폼 응용 프로그램을 만들고 있습니다. 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의 지침도 참고 하십시오.
https://github.com/joreilly/PeopleInSpace 에서 이것을 사용하기 시작
답변
[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
}
}
이 솔루션은 필요에 따라 쉽게 수정할 수 있습니다.
이 스레드 에서 자세한 정보를 찾을 수 있습니다 .
답변
때때로 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