SoFunction
Updated on 2025-04-10

Detailed explanation of the examples of three-finger revocation and copywriting limit length for iOS13

text

During the process of adapting to iOS 13,UITextFieldWhen entering Chinese, three fingers undo it generates crash.

Bugly reports an error

NSInternalInconsistencyException
setGroupIdentifier:: _NSUndoStack 0x1206532f0 is in invalid state, calling setGroupIdentifier with no begin group mark

Stack Information

 CoreFoundation	___exceptionPreprocess + 220
 	objc_exception_throw + 56
 Foundation	-[_NSUndoStack groupIdentifier]
 Foundation	-[NSUndoManager undoNestedGroup] + 240
 UIKitCore	-[UIUndoGestureInteraction undo:] + 72
 UIKitCore	-[UIKBUndoInteractionHUD performDelegateUndoAndUpdateHUDIfNeeded] + 96
 UIKitCore	-[UIKBUndoInteractionHUD controlActionUpInside:] + 152
 UIKitCore	-[UIApplication sendAction:to:from:forEvent:] + 96
 xxxxx	-[UIApplication(MemoryLeak) swizzled_sendAction:to:from:forEvent:] + 288
 UIKitCore	-[UIControl sendAction:to:forEvent:] + 240
 UIKitCore	-[UIControl _sendActionsForEvents:withEvent:] + 408
 UIKitCore	-[UIControl touchesEnded:withEvent:] + 520
 UIKitCore	-[UIWindow _sendTouchesForEvent:] + 2324
 UIKitCore	-[UIWindow sendEvent:] + 3352
 UIKitCore	-[UIApplication sendEvent:] + 336
 UIKitCore	___dispatchPreprocessedEventFromEventQueue + 5880
 UIKitCore	___handleEventQueueInternal + 4924
 UIKitCore	___handleHIDEventFetcherDrain + 108
 CoreFoundation	___CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
 CoreFoundation	___CFRunLoopDoSource0 + 80
 CoreFoundation	___CFRunLoopDoSources0 + 180
 CoreFoundation	___CFRunLoopRun + 1080
 CoreFoundation	CFRunLoopRunSpecific + 464
 GraphicsServices	GSEventRunModal + 104
 UIKitCore	UIApplicationMain + 1936
 xxxxx	main + 148
 	_start + 4

Problem positioning

When I didn’t have many ideas, I finally found the problem by commenting on the code.

[self addTarget:observer
         action:@selector(textChange:)
forControlEvents:UIControlEventEditingChanged];
- (void)textChange:(UITextField *)textField {
    ... ... 
    UITextRange *selectedRange = [textField markedTextRange];
    if (!selectedRange || !) {
        if ( > maxLength) {
             = [destText substringToIndex:maxLength];
        }
    }
}

This code will limit the length of the copy when entered. Three-finger revocation will triggerUIControlEventEditingChangedEvent, executiontextChange, obtained at this timemarkedTextRangeyesnilEven if it existsmarkedText. This leads toUITextFieldoftextIt may be modified. If you continue to perform the undo operation after modifying the copy, it will definitely cause crash.

Solution

Add copywriter judge and intercept asynchronously to the main queue, in the nextrunloopimplement.

- (void)textChange:(UITextField *)textField {
    dispatch_async(dispatch_get_main_queue(), ^{
        ... ...
    });
}

Crash after truncation of numbers

After the digital input limits the length, continue to input after exceeding the length. Undoing will also cause crash, and the above method is not feasible. The current plan isUITextFieldThe callback method performs input intercept.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    /// After entering a number, intercepting the string can still trigger the undo operation and cause crash. Intercept it here.    if ( == UIKeyboardTypeNumberPad
        &&  >= textField.tt_maxLength) {
            return NO;
    }
    return YES;
}

The above is the detailed explanation of the example of iOS13 adaptation to three-finger revocation and copywriting limit. For more information about iOS13 adaptation to three-finger revocation, please pay attention to my other related articles!