-
Notifications
You must be signed in to change notification settings - Fork 1.9k
iOS Dispatchers.Main.immediate behaves like non-immediate #4430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi! Thank you for the well-made reproducing project. This is not a bug, this behaviour is in line with the documentation. In this scenario, one coroutine running in
The event loop (described in https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html) has an unspecified order of events:
So, both behaviours you're showing are correct. There is no guarantee that collection will happen immediately. Please see #3760 for details. Despite not being a bug, I still think this is worth fixing, at least for consistency across platforms in a single project. Note, though, that we still reserve the right to change the ordering in a future release (but if we do that, we should do it for all platforms simultaneously). |
Hello, thank you kindly for your response and providing very insightful links. Especially, thank you very much for addressing this in a pull request to ensure platform consistency. I admit I missed the documentation part, where:
As a matter of fact, a long-time observed behavior felt so natural it was easy to assume it is only correct. If order of execution is an implementation detail, could you by any chance provide a hint on what would be the recommended approach to:
In short, how to achieve what we're actually are achieving now by taking advantage of implementation detail of Android's Dispatcher, but in a future-proof way? Would it be something like DirectDispatcher you already suggested to someone in #3506 (comment) ? At least two solutions I can think of that should work:
Any advice would be highly appreciated. |
Describe the bug
Having a multiplatform project targetting iOS and Android with shared Compose UI, we have observed a situation, where application started on iOS behaves differently than one on Android when running coroutines in
viewModelScope
, which, according to documentation at https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-viewmodel.html should be an immediate dispatcher (and also DarwinMainDispatcher implementation in kotlinx-coroutines-core suggests it should be supported).I am attaching a sample project that shows the issue. See AppViewModel.kt class in
commonMain
module and simply run the project on Android (I was using Pixel 7 API 34 Emulator and Samsung S24 with Android 14) and observe logcat by AppViewModel tag. Afterwards run the same project on iOS via Xcode (I was using iPhone 16 Pro Simulator with iOS 18.0) and observe console output there (also filtering by AppViewModel). Compare the logs.Consider the following piece of code, which is a part of the minimal project I'm attaching to this report:
Expected Behavior
As dispatcher used for viewModelScope is supposed to be immediate, collection should happen on the same stack as the new value has been emitted to
sharedFlow
. For the code above, below is the logcat output of Android project which I consider to be correct:The order of logs is correct for immediate dispatcher:
will emit second
->collected second
->secondSuccess = true
->will emit third
->collected third
->thirdSuccess = true
.Actual behavior on iOS
Below is the console output from iOS:
The order of logs suggests iOS Dispatcher does not behave in an immediate manner.
When a
second
value is attempted to be emitted, it would be expected thatcollect
would happen immediately in the same stack, as there is no thread change involved and it is supposed to be an immediate dispatcher. Yet there is nocollect
forsecond
at this point - it seems to happen out of stack, after an attempt to emitthird
fails. I understand thattryEmit
returns false when there is no chance to emit a value without suspending, but there should be no need for suspending in the example I'm showing.Provide a Reproducer
I am attaching a minimal example project below.
CoroutinesTest-minimal.zip
Environment summary
Android: Pixel 7 API 34 Emulator, Samsung S24 Android 14 (works as expected for both)
iOS: Simulator for iPhone 16 Pro with iOS 18.0
Library versions:
The text was updated successfully, but these errors were encountered: