SwiftUI internal state crash - minimal and complete repro case included

Originator:miguel.de.icaza
Number:rdar://FB11638212 Date Originated:2022-10-02
Status:open Resolved:
Product:SwiftUI Frameworks Product Version:16.0
Classification: Reproducible:yes
 
I have included the shortest full example I could make that triggers an NSInternalConsistencyException error when the state in SwiftUI triggers a TextField that is the first responder to be removed from the screen.

To reproduce, run the attached sample, and then tap “Password” on the Picker, then select the new text entry that appears, and go back and tap on the original option “SSH Key” in the picker.  This produces the following crash:

2022-10-02 18:17:31.182263-0400 BugSwiftUI[13782:47604798] *** Assertion failure in -[SwiftUI.UpdateCoalescingCollectionView _resignOrRebaseFirstResponderViewWithUpdateItems:indexPathMapping:], UICollectionView.m:11437
2022-10-02 18:17:31.189597-0400 BugSwiftUI[13782:47604798] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempt to delete item containing first responder that refused to resign.
First responder that was asked to resign (returned YES from -resignFirstResponder): <UITextField: 0x7ff0c183b000; frame = (0 0; 278.667 22); opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000117f90>; placeholder = •••••••; borderStyle = None; background = <_UITextFieldNoBackgroundProvider: 0x600000d50a90: textfield=<UITextField 0x7ff0c183b000>>; layer = <CALayer: 0x600000fe1260>> inside containing view: <SwiftUI.ListCollectionViewCell: 0x7ff0c1821800; baseClass = UICollectionViewListCell; frame = (20 79; 353 44); clipsToBounds = YES; layer = <CALayer: 0x600000fe6a60>> at index path: <NSIndexPath: 0xbefe45162b4a51ac> {length = 2, path = 0 - 1}
Current first responder: <_TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__: 0x7ff0c1833400; frame = (0 0; 353 44); autoresize = W+H; gestureRecognizers = <NSArray: 0x6000001eff00>; layer = <CALayer: 0x600000fe6d00>> inside containing view: <SwiftUI.ListCollectionViewCell: 0x7ff0c1821800; baseClass = UICollectionViewListCell; frame = (20 79; 353 44); clipsToBounds = YES; layer = <CALayer: 0x600000fe6a60>> at index path: <NSIndexPath: 0xbefe45162b4a51ac> {length = 2, path = 0 - 1}'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000010ef8c378 __exceptionPreprocess + 242
	1   libobjc.A.dylib                     0x000000010c958baf objc_exception_throw + 48
	2   Foundation                          0x000000010fdfa6ac _userInfoForFileAndLine + 0
	3   UIKitCore                           0x0000000121ba2c2f -[UICollectionView _resignOrRebaseFirstResponderViewWithUpdateItems:indexPathMapping:] + 1340
	4   UIKitCore                           0x0000000121ba09bc -[UICollectionView _updateWithItems:tentativelyForReordering:propertyAnimator:collectionViewAnimator:] + 226
	5   UIKitCore                           0x0000000121b9771b -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:collectionViewAnimator:] + 14344
	6   UIKitCore                           0x0000000121ba514c -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:animationHandler:] + 577
	7   UIKitCore                           0x0000000121ba4e7d -[UICollectionView performBatchUpdates:completion:] + 34
	8   SwiftUI                             0x000000010cea5c4f block_destroy_helper + 25991
	9   SwiftUI                             0x000000010cea6453 block_destroy_helper + 28043
	10  SwiftUI                             0x000000010d4dc85e __swift_memcpy56_4 + 159666
	11  SwiftUI                             0x000000010d04c3be block_destroy_helper.23 + 66721
	12  SwiftUI                             0x000000010d04c3d4 block_destroy_helper.23 + 66743
	13  UIKitCore                           0x0000000122c84eff +[UIView(Animation) performWithoutAnimation:] + 84
	14  SwiftUI                             0x000000010d4ddaa0 __swift_memcpy56_4 + 164340
	15  SwiftUI                             0x000000010d3cc8f8 objectdestroy.136Tm + 41411
	16  SwiftUI                             0x000000010d0ed86f block_destroy_helper + 35480
	17  SwiftUI                             0x000000010d0ed1d0 block_destroy_helper + 33785
	18  SwiftUI                             0x000000010cdd8a78 __swift_assign_boxed_opaque_existential_1 + 70088
	19  SwiftUI                             0x000000010cdd89db __swift_assign_boxed_opaque_existential_1 + 69931
	20  SwiftUI                             0x000000010cdd8ad1 __swift_assign_boxed_opaque_existential_1 + 70177
	21  CoreFoundation                      0x000000010eeeafe5 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
	22  CoreFoundation                      0x000000010eee5952 __CFRunLoopDoObservers + 515
	23  CoreFoundation                      0x000000010eee5e9d __CFRunLoopRun + 1161
	24  CoreFoundation                      0x000000010eee5637 CFRunLoopRunSpecific + 560
	25  GraphicsServices                    0x0000000112e4c28a GSEventRunModal + 139
	26  UIKitCore                           0x000000012266a425 -[UIApplication _run] + 994
	27  UIKitCore                           0x000000012266f301 UIApplicationMain + 123
	28  SwiftUI                             0x000000010d97efa3 __swift_memcpy53_8 + 95801
	29  SwiftUI                             0x000000010d97ee50 __swift_memcpy53_8 + 95462
	30  SwiftUI                             0x000000010d09eafc __swift_memcpy195_8 + 12192
	31  BugSwiftUI                          0x000000010c46236e $s10BugSwiftUI0aB5UIAppV5$mainyyFZ + 30
	32  BugSwiftUI                          0x000000010c4623f9 main + 9
	33  dyld                                0x000000010c6b32bf start_sim + 10
	34  ???                                 0x000000011a46452e 0x0 + 4735780142
)


The full text case is:

//
// Minimal SwiftUI crash sample
//
// To reproduce the crash:
//   1. Run the app and select "Password" on the toggle
//   2. Tap to focus the TextField
//   3. Tap on the selector on "SSH Key", this causes the crash:
//
// Stack trace at the bottom:
//
//  Created by Miguel de Icaza on 10/2/22.
//

import SwiftUI

struct HostEditView: View {
    @State var password = ""
    @State var usePassword = false
    
    func saveAndLeave () {}
    var body: some View {
        Form {
            HStack {
                Picker(selection: $usePassword, label: Text ("Auth")) {
                    Text ("Password")
                        .tag (true)
                    Text ("SSH Key")
                        .tag (false)
                }
                .pickerStyle(SegmentedPickerStyle())
                .frame(width: 160)
            }
            if usePassword {
                HStack {
                    TextField ("•••••••", text: self.$password)
                        .multilineTextAlignment(.trailing)
                        .autocapitalization(.none)
                    
                    
                    Button (action: {}, label: { Image(systemName: "eye") })
                }
            } else {
                Text ("SSH Key")
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        HostEditView()
    }
}

@main
struct BugSwiftUIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!