swiftuikitcore-location

UIKit CLLocationButton crash when I tap on a text field in the simulator


Please simulate the following app on Xcode's simulator:

import UIKit
import CoreLocationUI

class ViewController: UIViewController {
    let textField: UITextField = {
        let tf = UITextField()
        tf.backgroundColor = .systemGray6
        tf.placeholder = "Tap me"
        tf.leftView = UIView(frame: .init(x: 0, y: 0, width: 8, height: 0))
        tf.leftViewMode = .always
        tf.layer.cornerRadius = 11
        return tf
    }()
    let locationButton = CLLocationButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        
        view.addSubview(textField)
        view.addSubview(locationButton)
        
        textField.translatesAutoresizingMaskIntoConstraints = false
        locationButton.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            textField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
            textField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85),
            textField.heightAnchor.constraint(equalToConstant: 44),
            
            locationButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            locationButton.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 8),
            locationButton.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85),
            locationButton.heightAnchor.constraint(equalToConstant: 44),
        ])
    }
}

If I tap on the text field, the app crashes. Error message:

Thread 1: "*** -[__NSDictionaryM setObject:forKey:]: object cannot be nil (key: arrow.uturn.forward)".

Xcode 15.3, MacBook Air M1 8GB, macOS Sonoma 14.4, simulator os: iOS 17.4.

I've noticed that it doesn't crash on my iPhone SE 1st gen (iOS 15.8).

I don't have other iOS devices to try it on unfortunately.

Is this just a simulator bug?

Console log:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSDictionaryM setObject:forKey:]: object cannot be nil (key: arrow.uturn.forward)'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001804ae138 __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x0000000180087db4 objc_exception_throw + 56
    2   CoreFoundation                      0x000000018051e88c -[__NSDictionaryM setObject:forKey:] + 1232
    3   UIKitCore                           0x00000001856c0f44 +[UIAssistantBarButtonItemProvider configuredSymbolImageWithName:size:] + 344
    4   UIKitCore                           0x00000001856c00bc +[UIAssistantBarButtonItemProvider barButtonItemForAssistantItemStyle:target:forcePlainButton:] + 2120
    5   UIKitCore                           0x00000001856c1200 +[UIAssistantBarButtonItemProvider defaultSystemLeadingBarButtonGroupsForItem:] + 204
    6   UIKitCore                           0x00000001856c1754 +[UIAssistantBarButtonItemProvider systemDefaultAssistantItem] + 48
    7   UIKitCore                           0x0000000185417e0c -[UIResponder(UIResponderInputViewAdditions) inputAssistantItem] + 64
    8   UIKitCore                           0x0000000185717710 -[UITextField inputAssistantItem] + 64
    9   UIKitCore                           0x0000000185417d4c _UIResponderFindInputAssistantItem + 44
    10  UIKitCore                           0x0000000184d79c18 -[UISystemInputAssistantViewController isVisibleWhenMinimized] + 96
    11  UIKitCore                           0x000000018523c12c +[UIPeripheralHost(UIKitInternal) endPlacementForInputViewSet:windowScene:] + 1292
    12  UIKitCore                           0x0000000184e0b2d0 -[UIKeyboardSceneDelegate prepareToMoveKeyboardForInputViewSet:animationStyle:] + 192
    13  UIKitCore                           0x0000000184e0a060 -[UIKeyboardSceneDelegate setKeyWindowSceneInputViews:animationStyle:] + 1396
    14  UIKitCore                           0x0000000184e09ab8 -[UIKeyboardSceneDelegate setInputViews:animationStyle:] + 132
    15  UIKitCore                           0x0000000184e0aaa4 -[UIKeyboardSceneDelegate setInputViews:animated:] + 72
    16  UIKitCore                           0x0000000184e0aaf4 -[UIKeyboardSceneDelegate setInputViews:] + 52
    17  UIKitCore                           0x0000000184e081f0 __102-[UIKeyboardSceneDelegate _reloadInputViewsForKeyWindowSceneResponder:force:fromBecomeFirstResponder:]_block_invoke.484 + 24
    18  UIKitCore                           0x00000001852386e0 __65-[UIPeripheralHost(UIKitInternal) queueDelayedTask:forKey:delay:]_block_invoke + 156
    19  libdispatch.dylib                   0x00000001016fd73c _dispatch_client_callout + 16
    20  libdispatch.dylib                   0x0000000101700c14 _dispatch_continuation_pop + 756
    21  libdispatch.dylib                   0x00000001017164e0 _dispatch_source_invoke + 1736
    22  libdispatch.dylib                   0x000000010170d2a8 _dispatch_main_queue_drain + 892
    23  libdispatch.dylib                   0x000000010170cf1c _dispatch_main_queue_callback_4CF + 40
    24  CoreFoundation                      0x000000018040e9a0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    25  CoreFoundation                      0x00000001804090b8 __CFRunLoopRun + 1936
    26  CoreFoundation                      0x0000000180408514 CFRunLoopRunSpecific + 572
    27  GraphicsServices                    0x000000018ef06ae4 GSEventRunModal + 160
    28  UIKitCore                           0x00000001853e8040 -[UIApplication _run] + 868
    29  UIKitCore                           0x00000001853ebcc8 UIApplicationMain + 124
    30  UIKitCore                           0x000000018488c1cc __swift_destroy_boxed_opaque_existential_1Tm + 10048
    31  Crash_CLLocationButton              0x000000010057044c $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 120
    32  Crash_CLLocationButton              0x00000001005703c4 $s22Crash_CLLocationButton11AppDelegateC5$mainyyFZ + 44
    33  Crash_CLLocationButton              0x00000001005704c8 main + 28
    34  dyld                                0x00000001005d1544 start_sim + 20
    35  ???                                 0x00000001006e60e0 0x0 + 4302201056
    36  ???                                 0x027c800000000000 0x0 + 179158822676332544
)
libc++abi: terminating due to uncaught exception of type NSException

Solution

  • This is definitely an iOS bug that appears when the app is run on an iPad or iPad simulator with iOS 17. The crash does not happen with iOS 15 or 16 (at least with iOS 15.5 or 16.4).

    The error mentions a value of arrow.uturn.forward. This is an SF Symbol name typically used for the "Redo" button shown in the toolbar of an iPad keyboard.

    If the app creates an instance of CLLocationButton (regardless of whether the button is added to the view hierarchy or not), the bug appears. Under iOS 17 the app crashes as shown in the question. Under iOS 15 and 16, the crash does not happen but the normal undo/redo/paste icons are replaced by the words "Undo"/"Redo"/Paste". Oddly, under iOS 16, the paste button shows both the word "Paste" and the paste icon overlaid on each other.

    There is a work around. Add the following two lines to the UITextField setup code:

    tf.inputAssistantItem.leadingBarButtonGroups = []
    tf.inputAssistantItem.trailingBarButtonGroups = []
    

    Those two lines remove the buttons from the iPad keyboard toolbar which in turn prevents the crash. It may not be ideal to remove those toolbar items but it is better than the app crashing.

    Meanwhile, use the Feedback Assistant app and submit a complete test app using your code as a demonstration for this bug. Feel free to include info from this answer as well.