Skip to content
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

App crashes when Compose SwfitUI View container removed from hierarchy. #4315

Closed
dmytro-fido opened this issue Feb 16, 2024 · 2 comments · Fixed by JetBrains/compose-multiplatform-core#1114
Labels
bug Something isn't working duplicate This issue or pull request already exists ios

Comments

@dmytro-fido
Copy link

Describe the bug
App crashes when Compose SwfitUI View container removed from hierarchy.
Crash happens in ComposeContainer.windowContainer line 102

        get() = if (configuration.platformLayers) checkNotNull(view.window) {
            "ComposeUIViewController.view should be attached to window"
        } else view

view.window is null when viewWillLayoutSubviews called.

stack trace:

Uncaught Kotlin exception: kotlin.IllegalStateException: ComposeUIViewController.view should be attached to window
    at 0   dev                                 0x104b7a673        kfun:kotlin.Throwable#<init>(kotlin.String?){} + 119 
    at 1   dev                                 0x104b73aeb        kfun:kotlin.Exception#<init>(kotlin.String?){} + 115 
    at 2   dev                                 0x104b73dff        kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 115 
    at 3   dev                                 0x104b74333        kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 115 
    at 4   dev                                 0x105c14def        kfun:androidx.compose.ui.window.ComposeContainer.<get-windowContainer>#internal + 587 
    at 5   dev                                 0x105c16f8f        kfun:androidx.compose.ui.window.ComposeContainer#objc:viewWillLayoutSubviews + 759 
    at 6   dev                                 0x105c1d233        _6f72672e6a6574627261696e732e636f6d706f73652e75693a75692f6f70742f6275696c644167656e742f776f726b2f383339343731666333323931333563372f636f6d706f73652f75692f75692f7372632f75696b69744d61696e2f6b6f746c696e2f616e64726f6964782f636f6d706f73652f75692f77696e646f772f436f6d706f7365436f6e7461696e65722e75696b69742e6b74_knbridge130 + 215 
    at 7   UIKitCore                           0x1b346a82f        <redacted> + 1047 
    at 8   QuartzCore                          0x1b2925073        <redacted> + 499 
    at 9   QuartzCore                          0x1b29385ef        <redacted> + 147 
    at 10  QuartzCore                          0x1b2949a1b        <redacted> + 443 
    at 11  QuartzCore                          0x1b2978ff3        <redacted> + 647 
    at 12  QuartzCore                          0x1b2962f3b        <redacted> + 87 
    at 13  CoreFoundation                      0x1b1487233        <redacted> + 35 
    at 14  CoreFoundation                      0x1b141140f        <redacted> + 531 
    at 15  CoreFoundation                      0x1b147119b        <redacted> + 1027 
    at 16  CoreFoundation                      0x1b14763eb        CFRunLoopRunSpecific + 611 
    at 17  GraphicsServices                    0x1ec91335b        GSEventRunModal + 163 
    at 18  UIKitCore                           0x1b38036e7        <redacted> + 887 
    at 19  UIKitCore                           0x1b380334b        UIApplicationMain + 339 
    at 20  libswiftUIKit.dylib                 0x1b9e8b0af        $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 103 
    at 21  dev                                 0x10235b943        $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 119 
    at 22  dev                                 0x10235b8bb        $s3dev11AppDelegateC5$mainyyFZ + 43 
    at 23  dev                                 0x10235cecb        main + 27 
    at 24  dyld                                0x1d094edeb        <redacted> + 2219 

Affected platforms
Select one of the platforms below:

  • iOS

Versions

  • Kotlin version*: 1.9.22
  • Compose Multiplatform version*: 1.6.0-rc01
  • OS version(s)* (required for Desktop and iOS issues): iOS 16.5.1
  • OS architecture (x86 or arm64): arn64
  • JDK (for desktop issues):

To Reproduce
Steps and/or the code snippet to reproduce the behaviour:
CustomBottomSheetUIViewController:

fun CustomBottomSheetUIViewController(
    onDismissRequest: () -> Unit,
    content: @Composable () -> Unit,
): UIViewController = ComposeUIViewController(
    configure = {
        opaque = false
    },
) {
    val bottomSheetController = rememberModalBottomSheetController()
    ModalBottomSheet(
        onDismissRequest = { bottomSheetController.dismiss(onDismissRequest) },
        sheetState = bottomSheetController.sheetState,
    ) {
        content()
    }
}

where rememberModalBottomSheetController is:

class ModalBottomSheetController(
    private val coroutineScope: CoroutineScope,
    val sheetState: SheetState,
) {

    fun dismiss(onDismissAnimationEnds: () -> Unit) {
        coroutineScope.launch { sheetState.hide() }.invokeOnCompletion {
            onDismissAnimationEnds()
        }
    }
}

@Composable
fun rememberModalBottomSheetController(
    coroutineScope: CoroutineScope = rememberCoroutineScope(),
    sheetState: SheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
) = remember(coroutineScope, sheetState) {
    ModalBottomSheetController(coroutineScope, sheetState)
}

usage of custom controller from Compose code:

fun CustomBottomSheetUiView(
    viewModel: ViewModel,
    navigator: Navigator,
): UIViewController = CustomBottomSheetUIViewController(
    onDismissRequest = viewModel::onDismissRequest,
) {
        SharedBottomSheet(
            viewModel = viewModel,
            navigator = navigator,
        )
}

usage in SwfitUi:

struct CustomBottomSheet: View {

    private var viewModel: ViewModel
    private let navigator: Navigator
    
    init(bottomSheetData: BottomSheetData, navigator: Navigator) {
        self.viewModel = getViewModel(bottomSheetData: bottomSheetData)
        self.navigator = navigator
    }

    var body: some View {
        VStack {
            CustomBottomSheetView(
                viewModel: viewModel,
                navigator: navigator
            )
        }
        .ignoresSafeArea()
        .statusBarHidden()
    }
}

private func getViewModel(bottomSheetData: BottomSheetData) -> ViewModel {
    Koin.shared.get(
        parameters: ViewModel.companion.parameters(
            bottomSheetData: bottomSheetData
        )
    )
}

private struct CustomBottomSheetView: UIViewControllerRepresentable {
    let viewModel: ViewModel
    let navigator: Navigator

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
    
    func makeUIViewController(context: Context) -> some UIViewController {
        KotlinFileNameKt.CustomBottomSheetUiView(
            viewModel: viewModel,
            navigator: navigator
        )
    }
}

When onDismissRequest triggered, SwiftUi code removes CustomBottomSheetView from hierarchy:

    func dismissBottomSheet() {
        bottomSheetData = nil
    }

 if let bottomSheetData = bottomSheetData {
            CustomBottomSheet(
                bottomSheetData: bottomSheetData,
                navigator: goodsPickupLocationDetailsBottomSheetNavigator()
            )
        }

Expected behavior
App doesn't crash when View holding ComposeUIViewController removed from hierarchy

Additional context
when ComposeUIViewController created with plarformLayers = false, stack trace is different:
it crashes in SemanticsOwnerListenerImpl.onSemanticsOwnerRemoved line 126
val current = checkNotNull(current)
when onSemanticsOwnerRemoved is called, current is null.

ComposeUIViewController(
    configure = {
        platformLayers = false
        opaque = false
    },
)
Uncaught Kotlin exception: kotlin.IllegalStateException: Required value was null.
    at 0   dev                                 0x1081f65d3        kfun:kotlin.Throwable#<init>(kotlin.String?){} + 119 
    at 1   dev                                 0x1081efa4b        kfun:kotlin.Exception#<init>(kotlin.String?){} + 115 
    at 2   dev                                 0x1081efd5f        kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 115 
    at 3   dev                                 0x1081f0293        kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 115 
    at 4   dev                                 0x1092819a7        kfun:androidx.compose.ui.scene.SemanticsOwnerListenerImpl.onSemanticsOwnerRemoved#internal + 395 
    at 5   dev                                 0x109ef4657        kfun:androidx.compose.ui.platform.PlatformContext.SemanticsOwnerListener#onSemanticsOwnerRemoved(androidx.compose.ui.semantics.SemanticsOwner){}-trampoline + 99 
    at 6   dev                                 0x10921f897        kfun:androidx.compose.ui.scene.MultiLayerComposeSceneImpl.onOwnerRemoved#internal + 479 
    at 7   dev                                 0x10921fcfb        kfun:androidx.compose.ui.scene.MultiLayerComposeSceneImpl.detachLayer#internal + 475 
    at 8   dev                                 0x1092227c7        kfun:androidx.compose.ui.scene.MultiLayerComposeSceneImpl.AttachedComposeSceneLayer.close#internal + 191 
    at 9   dev                                 0x10921c74b        kfun:androidx.compose.ui.scene.MultiLayerComposeSceneImpl.close#internal + 963 
    at 10  dev                                 0x109ef5e8f        kfun:androidx.compose.ui.scene.ComposeScene#close(){}-trampoline + 91 
    at 11  dev                                 0x10927284f        kfun:androidx.compose.ui.scene.ComposeSceneMediator#dispose(){} + 611 
    at 12  dev                                 0x1092961e7        kfun:androidx.compose.ui.window.ComposeContainer.dispose#internal + 251 
    at 13  dev                                 0x10929530f        kfun:androidx.compose.ui.window.ComposeContainer#objc:viewControllerDidLeaveWindowHierarchy + 235 
    at 14  dev                                 0x1092999f3        _6f72672e6a6574627261696e732e636f6d706f73652e75693a75692f6f70742f6275696c644167656e742f776f726b2f383339343731666333323931333563372f636f6d706f73652f75692f75692f7372632f75696b69744d61696e2f6b6f746c696e2f616e64726f6964782f636f6d706f73652f75692f77696e646f772f436f6d706f7365436f6e7461696e65722e75696b69742e6b74_knbridge143 + 215 
    at 15  libdispatch.dylib                   0x117786037        _dispatch_client_callout + 19 
    at 16  libdispatch.dylib                   0x1177891b3        _dispatch_continuation_pop + 791 
    at 17  libdispatch.dylib                   0x11779fe2f        _dispatch_source_invoke + 1659 
    at 18  libdispatch.dylib                   0x1177965f7        _dispatch_main_queue_drain + 779 
    at 19  libdispatch.dylib                   0x1177962db        _dispatch_main_queue_callback_4CF + 43 
    at 20  CoreFoundation                      0x1b148fc27        <redacted> + 15 
    at 21  CoreFoundation                      0x1b147155f        <redacted> + 1991 
    at 22  CoreFoundation                      0x1b14763eb        CFRunLoopRunSpecific + 611 
    at 23  GraphicsServices                    0x1ec91335b        GSEventRunModal + 163 
    at 24  UIKitCore                           0x1b38036e7        <redacted> + 887 
    at 25  UIKitCore                           0x1b380334b        UIApplicationMain + 339 
    at 26  libswiftUIKit.dylib                 0x1b9e8b0af        $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 103 
    at 27  dev                                 0x1059d78a3        $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 119 
    at 28  dev                                 0x1059d781b        $s3dev11AppDelegateC5$mainyyFZ + 43 
    at 29  dev                                 0x1059d8e2b        main + 27 
    at 30  dyld                                0x1d094edeb        <redacted> + 2219 
@dmytro-fido dmytro-fido added bug Something isn't working submitted labels Feb 16, 2024
@MatkovIvan
Copy link
Member

Duplicate of #4310, already fixed but will be included only to rc03

@MatkovIvan MatkovIvan added duplicate This issue or pull request already exists ios and removed submitted labels Feb 16, 2024
@MatkovIvan
Copy link
Member

@elijah-semyonov ptal on the case in SemanticsOwnerListenerImpl too, it looks different

MatkovIvan pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Feb 17, 2024
… early exit instead (#1114)

## Proposed Changes

Replace throwing `SemanticsOwnerListenerImpl.current` check with early
exit check.

## Testing

Test: N/A

## Issues Fixed

Fixes: JetBrains/compose-multiplatform#4315
igordmn pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Feb 19, 2024
… early exit instead (#1114)

## Proposed Changes

Replace throwing `SemanticsOwnerListenerImpl.current` check with early
exit check.

## Testing

Test: N/A

## Issues Fixed

Fixes: JetBrains/compose-multiplatform#4315
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working duplicate This issue or pull request already exists ios
Projects
None yet
2 participants