shaps80 / SwiftUIBackports

A collection of SwiftUI backports for iOS, macOS, tvOS and watchOS
MIT License
931 stars 59 forks source link

crash on orientation change when using .sheet with backported .presentationDetents and .interactiveDismissDisabled #62

Closed roland-schmitz-ocu closed 9 months ago

roland-schmitz-ocu commented 10 months ago

General Information

Describe the bug

When opening a sheet which has the backported .presentationDetents and .interactiveDismissDisabled view modifiers applied and then changing the device orientation from portrait to landscape and back, then the app crashes. The stack traces are showing an endless recursion.

Steps to reproduce

  1. Create a new app project in Xcode
  2. Replace the ContentView with this code:
import SwiftUI
import SwiftUIBackports

struct ContentView: View {
    @State private var showSheet = false

    var body: some View {
        Button("Show Sheet") {
            showSheet.toggle()
        }
        .sheet(isPresented: $showSheet) {
            Button("Hide Sheet") {
                showSheet.toggle()
            }
            .backport.presentationDetents([.medium])
            .backport.interactiveDismissDisabled(true)
        }
    }
}
  1. Run the app
  2. Open the sheet by tapping the "Show Sheet" button
  3. Change the interface orientation to landscape by rotating the device (or simulator)
  4. Change the interface orientation back to portrait.

For me this always crashes because of an endless recursion

Expected behavior

No crash

Stack trace, compiler error, code snippets

    Thread 1 Queue : com.apple.main-thread (serial)
    #0  0x000000018bfba694 in char* __swift::__runtime::llvm::hashing::detail::hash_combine_recursive_helper::combine_data<swift::TargetProtocolDescriptor<swift::InProcess> const*>(unsigned long&, char*, char*, swift::TargetProtocolDescriptor<swift::InProcess> const*) ()
    #1  0x000000018bfba610 in __swift::__runtime::llvm::hash_code __swift::__runtime::llvm::hash_combine<swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolDescriptor<swift::InProcess> const*>(swift::TargetMetadata<swift::InProcess> const* const&, swift::TargetProtocolDescriptor<swift::InProcess> const* const&) ()
    #2  0x000000018bfba4ac in std::__1::pair<(anonymous namespace)::ConformanceCacheEntry*, unsigned int> swift::ConcurrentReadableHashMap<(anonymous namespace)::ConformanceCacheEntry, swift::LazyMutex>::find<(anonymous namespace)::ConformanceCacheKey>((anonymous namespace)::ConformanceCacheKey const&, swift::ConcurrentReadableHashMap<(anonymous namespace)::ConformanceCacheEntry, swift::LazyMutex>::IndexStorage, unsigned long, (anonymous namespace)::ConformanceCacheEntry*) ()
    #3  0x000000018bfb97c8 in swift_conformsToProtocolMaybeInstantiateSuperclasses(swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolDescriptor<swift::InProcess> const*, bool) ()
    #4  0x000000018bfb8e5c in swift_conformsToProtocol ()
    #5  0x000000018bf7a1e8 in swift::_conformsToProtocol(swift::OpaqueValue const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolDescriptorRef<swift::InProcess>, swift::TargetWitnessTable<swift::InProcess> const**) ()
    #6  0x000000018bf80690 in _conformsToProtocols(swift::OpaqueValue const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetExistentialTypeMetadata<swift::InProcess> const*, swift::TargetWitnessTable<swift::InProcess> const**) ()
    #7  0x000000018bf7f788 in tryCastToConstrainedOpaqueExistential(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) ()
    #8  0x000000018bf7e488 in tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) ()
    #9  0x000000018bf7e0cc in swift_dynamicCast ()
    #10 0x000000018bd53150 in _debugPrint_unlocked<τ_0_0, τ_0_1>(_:_:) ()
    #11 0x000000018bdea750 in specialized _debugPrint<τ_0_0>(_:separator:terminator:to:) ()
    #12 0x000000018bddd440 in Optional.debugDescription.getter ()
    #13 0x000000018bd969a8 in String.init<τ_0_0>(describing:) ()
    #14 0x0000000102ca072c in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/Detents.swift:228
    #15 0x0000000102ca09e0 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #16 0x0000000102ca83ac in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/InteractiveDismiss.swift:223
    #17 0x0000000102ca8484 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #18 0x0000000102ca0908 in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/Detents.swift:230
    #19 0x0000000102ca09e0 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #20 0x0000000102ca83ac in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/InteractiveDismiss.swift:223
    #21 0x0000000102ca8484 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #22 0x0000000102ca0908 in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/Detents.swift:230
    #23 0x0000000102ca09e0 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #24 0x0000000102ca83ac in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/InteractiveDismiss.swift:223

    ...

    #38644  0x0000000102ca83ac in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/InteractiveDismiss.swift:223
    #38645  0x0000000102ca8484 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #38646  0x0000000102ca0908 in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/Detents.swift:230
    #38647  0x0000000102ca09e0 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #38648  0x0000000102ca83ac in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/InteractiveDismiss.swift:223
    #38649  0x0000000102ca8484 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #38650  0x0000000102ca0908 in Backport<τ_0_0>.Representable.Controller.responds(to:) at .../Repos/SwiftUIBackports/Sources/SwiftUIBackports/iOS/Presentation/Detents.swift:230
    #38651  0x0000000102ca09e0 in @objc Backport<τ_0_0>.Representable.Controller.responds(to:) ()
    #38652  0x0000000104b32eb0 in -[UISheetPresentationController _sheetLayoutInfoDidInvalidateUntransformedFrame:] ()
    #38653  0x00000001041837bc in _UISheetLayoutInfoDirtyUntransformedFrame ()
    #38654  0x0000000104184014 in _UISheetLayoutInfoDirtyOffsetAdjustment ()
    #38655  0x0000000104183ec0 in _UISheetLayoutInfoDirtyPercentFullHeight ()
    #38656  0x00000001041832f8 in _UISheetLayoutInfoDirtyStackAlignmentFrame ()
    #38657  0x0000000104183378 in _UISheetLayoutInfoDirtyMargins ()
    #38658  0x0000000104184434 in _UISheetLayoutInfoDirtyMarginsWhenFloating ()
    #38659  0x000000010417c448 in -[_UISheetLayoutInfo _setContainerSafeAreaInsets:] ()
    #38660  0x0000000104b32cfc in -[UISheetPresentationController _updateLayoutInfoContainerSafeAreaInsets] ()
    #38661  0x0000000104d52c38 in -[UITransitionView safeAreaInsetsDidChange] ()
    #38662  0x0000000104d63508 in -[UIView _safeAreaInsetsDidChangeFromOldInsets:] ()
    #38663  0x0000000104d62d44 in -[UIView _updateSafeAreaInsets] ()
    #38664  0x0000000104d6a27c in -[UIView _updateCombinedInsetsIfNecessary] ()
    #38665  0x0000000104d6f918 in -[UIView(Geometry) setFrame:] ()
    #38666  0x0000000104d52bcc in -[UITransitionView setFrame:] ()
    #38667  0x0000000104d71ccc in -[UIView(Geometry) _resizeWithOldSuperviewSize:] ()
    #38668  0x000000018039e934 in __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ ()
    #38669  0x00000001803253a8 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
    #38670  0x0000000104d7109c in -[UIView(Geometry) resizeSubviewsWithOldSize:] ()
    #38671  0x0000000104d6f83c in -[UIView(Geometry) setFrame:] ()
    #38672  0x000000010492911c in -[UIWindow setFrame:] ()
    #38673  0x00000001048e9e58 in -[UIApplication setStatusBarOrientation:fromOrientation:windowScene:animationParameters:updateBlock:] ()
    #38674  0x00000001049243a0 in __78-[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:]_block_invoke ()
    #38675  0x00000001042821fc in __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2 ()
    #38676  0x0000000104d80bdc in +[UIView _performBlockDelayingTriggeringResponderEvents:forScene:] ()
    #38677  0x000000010428208c in __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke ()
    #38678  0x0000000104d7e6b0 in +[UIView(UIViewAnimationWithBlocksPrivate) _modifyAnimationsWithPreferredFrameRateRange:updateReason:animations:] ()
    #38679  0x0000000104d7d584 in +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
    #38680  0x0000000104d7d96c in +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] ()
    #38681  0x0000000104281ef4 in -[_UIWindowRotationAnimationController animateTransition:] ()
    #38682  0x0000000104921cfc in -[UIWindow _rotateToBounds:withAnimator:transitionContext:] ()
    #38683  0x0000000104924154 in -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] ()
    #38684  0x0000000104924594 in -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] ()
    #38685  0x0000000104920f80 in -[UIWindow _internal_setRotatableViewOrientation:updateStatusBar:duration:force:] ()
    #38686  0x0000000104922c18 in __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke ()
    #38687  0x000000010492296c in -[UIWindow _updateToInterfaceOrientation:duration:force:] ()
    #38688  0x000000010403bc04 in -[_UIScenefbsSceneBasedMetricsCalculator _updateMetricsOnWindows:animated:] ()
    #38689  0x0000000104b18588 in -[UIWindowScene _computeMetricsForWindows:animated:] ()
    #38690  0x0000000104b17b68 in __55-[UIWindowScene _computeMetrics:withTransitionContext:]_block_invoke ()
    #38691  0x0000000104b17ca8 in -[UIWindowScene _computeTraitCollectionAndCoordinateSpaceForcingDelegateCallback:withAction:] ()
    #38692  0x0000000104b17af8 in -[UIWindowScene _computeMetrics:withTransitionContext:] ()
    #38693  0x0000000104b14ca8 in -[UIWindowScene _computeMetricsAndCrossFadeInLiveResize:withTransitionContext:] ()
    #38694  0x0000000104d7d584 in +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
    #38695  0x0000000104d7d7b0 in +[UIView(UIViewAnimationWithBlocks) _animateWithDuration:delay:options:factory:animations:completion:] ()
    #38696  0x000000010441d618 in +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:] ()
    #38697  0x000000010451d0d4 in _UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion ()
    #38698  0x0000000104040aa8 in -[_UIWindowSceneGeometrySettingsDiffAction _updateSceneGeometryWithSettingObserverContext:windowScene:transitionContext:] ()
    #38699  0x0000000104040718 in -[_UIWindowSceneGeometrySettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] ()
    #38700  0x0000000103eb0b3c in __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.196 ()
    #38701  0x0000000103eaf93c in -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] ()
    #38702  0x0000000103eb07f8 in -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] ()
    #38703  0x00000001044435d8 in -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] ()
    #38704  0x0000000184e593d4 in -[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:] ()
    #38705  0x0000000184e810d0 in __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke_2 ()
    #38706  0x0000000184e64704 in -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] ()
    #38707  0x0000000184e8101c in __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke ()
    #38708  0x0000000103bc9d50 in _dispatch_client_callout ()
    #38709  0x0000000103bcd968 in _dispatch_block_invoke_direct ()
    #38710  0x0000000184e9ef14 in __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ ()
    #38711  0x0000000184e9ee08 in -[FBSSerialQueue _targetQueue_performNextIfPossible] ()
    #38712  0x0000000184e9ef48 in -[FBSSerialQueue _performNextFromRunLoopSource] ()
    #38713  0x000000018039ac6c in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
    #38714  0x000000018039abb4 in __CFRunLoopDoSource0 ()
    #38715  0x000000018039a324 in __CFRunLoopDoSources0 ()
    #38716  0x0000000180394958 in __CFRunLoopRun ()
    #38717  0x0000000180394254 in CFRunLoopRunSpecific ()
    #38718  0x0000000188eb7c9c in GSEventRunModal ()
    #38719  0x00000001048e2ff0 in -[UIApplication _run] ()
    #38720  0x00000001048e6f3c in UIApplicationMain ()
    #38721  0x00000001089b734c in ___lldb_unnamed_symbol203070 ()
    #38722  0x00000001089b71ec in ___lldb_unnamed_symbol203068 ()
    #38723  0x00000001081af474 in static App.main() ()
    #38724  0x0000000102bc568c in static BackportSheetLocalApp.$main() at .../Repos/Experiments/BackportSheetLocal/BackportSheetLocal/BackportSheetLocalApp.swift:10
    #38725  0x0000000102bc5738 in main ()
    #38726  0x0000000103209514 in start_sim ()
    #38727  0x0000000103335f28 in start ()

Workaround

I will create a PR with two simple changes to avoid this endless recursion.

shaps80 commented 10 months ago

Interesting, I thought my original implementation considered this but I kinda get what you're saying. I've commented on the PR, thanks for this 👍