Closed gradha closed 8 months ago
Hi @gradha ! Thank you for reporting the problem. The lifecycle in Compose for iOS is indeed different from that on Android. We see that it causes different issues and we plan to approach this problem relatively soon. Unfortunately, there is no workaround for now, afaik. We'll post an update here as soon as we have any news.
Hi! We also are facing this issue. For now we found a workaround that seems to work. We have yet to find any side effects.
By following the steps to use a UIKit/SwiftUI View/ViewControllers within compose we sidestep leaving the context.
This is not an ideal solution and a fix would be greatly appreciated. But this might allow others to continue working while they wait.
Link to docs on how to achieve this: https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-ios-ui-integration.html#use-uikit-inside-compose-multiplatform
❤️
Any updates regarding this issue ?
It's quite a critical bug, for example, it prevents using a Camera through the KMP implementation - which is a crucial part of features for some applications
the easiest way to reproduce is using UITabBarController:
final class RootTabBarController: UITabBarController {
override func loadView() {
super.loadView()
let composePage = PagesKt.settingsPage()
let nativePage = UIViewController()
viewControllers = [composePage, nativePage]
}
}
not only DisposableEffect
is triggered, but also all remember states are lost. the whole page is reset to initial.
any update?
the easiest way to reproduce is using UITabBarController:
final class RootTabBarController: UITabBarController { override func loadView() { super.loadView() let composePage = PagesKt.settingsPage() let nativePage = UIViewController() viewControllers = [composePage, nativePage] } }
not only
DisposableEffect
is triggered, but also all remember states are lost. the whole page is reset to initial.
1.6.2 seems to solved this problem!
This should have been fixed in https://github.com/JetBrains/compose-multiplatform-core/commit/3083693a90f550c86ff84153bea0ab77892635c2.
Happened due to wrong reassigning of content
that triggered global recomposition on viewWillAppear
.
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
Describe the bug
After implementing a very basic and rudimentary navigation between screens that calls under the hood
startActivity
on Android andpushViewController
on iOS, I started to notice unexpected behaviour, which might be related to #3889. On AndroidLaunchedEffect
andDisposableEffect
execute once per activity lifetime, but on iOS they would be called every time theUIViewController
left the screen, even if the navigation was deeper into further view controllers, not back.Affected platforms Select one of the platforms below:
Versions
To Reproduce
The pull request at this fork of the ios compose template contains the whole code. A
ProxyNavigator
interface is created and passed on to the compose screens, so that interaction in those screens can call back code implemented by the native platform:The implementation of this interface on Android is fairly trivial:
On iOS it is slightly more awkward, it adds a view controller weak variable to capture the result of calling
ComposeUIViewController
:In both platforms the example app starts with basic root view, which then will open the first screen, and this in turn will add the second screen.
As can be seen, the compose button will call
proxyNavigator.openNext()
, which under the hood will either start another activity on android or push a new view controller on iOS. The second screen is just a dummy to highlight the effect.When running the android app, the root screen opens the first screen, and the
LaunchedEffect
triggers once. The entry point of theDisposableEffect
also triggers once. Now you can open the second screen and go back to the first as many times as you want, and no other side effects will trigger. Only when going back from the first screen to the root one will theonDispose
trigger happen.On the other hand, on iOS if you navigate from root -> First -> second, when entering second screen you will see that the dispose effects are triggered through logs. Going back and forth between the first and second screens will trigger all the launch and disposable side effects.
Expected behavior On iOS the launch side effect should trigger once when entering the screen, but it triggers when you navigate back from the second to the first view controllers. Same thing with the disposable side effects, they should happen once, but they happen every time the user leaves the screen from the first to the second and back.
Additional context I haven't tested this on SwiftUI, but I'm trying to integrate compose views into an old iOS architecture that uses UIViewController. The need for the Proxy navigation hack is really ugly because there's no way to access the opaque
UIViewController
created by compose multiplatform. This is making navigation quite messy with all the circular references and extra attributes.Even
ComposeUIViewControllerConfiguration
could alleviate these hacks if the interface implemented passing as first parameter the view controller:With this kind of interface I would not need to store the
UIViewController
in extra variables, or rather could capture it insideviewDidLoad
to later use it for navigation.