Search code examples
iphoneiosipaduitextfieldnsundomanager

UITextField replace text with NSUndoManager Support


I'm just using a simple

self.customerTextField.text = @"text";

but I would like there to be undo support, where if they shake the phone they can undo the change.

I'm kinda at a loss as to how to accomplish this. All the exapmles I find are for UITextView.

======================== Current iteration of code ======================

-(void)getUniqueItemID {

    [self.inventoryLibrarian generateUniqueItemIDwithCompletionBlock:^(NSString *string) {

        [self undoTextFieldEdit:string];
        //self.customTextField.text = string;

    }];

}

- (void)undoTextFieldEdit: (NSString*)string
{
    [self.undoManager registerUndoWithTarget:self
                                    selector:@selector(undoTextFieldEdit:)
                                      object:self.customTextField.text];
    self.customTextField.text = string;
}

-(BOOL)canBecomeFirstResponder {
    return YES;
}

Solution

  • Shake-to-undo
    Put this line in your appDelegate's application:didFinishLaunchingWithOptions: method:

        application.applicationSupportsShakeToEdit = YES;
    

    and in the relevant viewController.m

        -(BOOL)canBecomeFirstResponder {
            return YES;
        }
    

    the rest of this code goes in viewController.m

    Property
    Put this in the class extension...

        @interface myViewController()
        @property (weak, nonatomic) IBOutlet UITextField *inputTextField;
        @end
    

    link it up to your text field in Interface Builder.

    Undo method
    Adds an invocation of itself to the redo stack

        - (void)undoTextFieldEdit: (NSString*)string
        {
            [self.undoManager registerUndoWithTarget:self
                                            selector:@selector(undoTextFieldEdit:)
                                              object:self.inputTextField.text];
            self.inputTextField.text = string;
        }
    

    (we do not need to create an NSUndoManager instance, we inherit one from the UIResponder superclass)

    Undo actions
    Not required for shake-to-undo, but could be useful...

        - (IBAction)undo:(id)sender {
            [self.undoManager undo];
        }
        - (IBAction)redo:(id)sender {
            [self.undoManager redo];
        }
    

    Invocations of the undo method
    Here are two different examples of changing the textField's contents…

    Example 1
    Set the textField's contents from a button action

        - (IBAction)addLabelText:(UIButton*)sender {
            [self.undoManager registerUndoWithTarget:self
                                            selector:@selector(undoTextFieldEdit:)
                                              object:self.inputTextField.text];
            self.inputTextField.text = @"text";
        }
    

    Risking loss of clarity, we can shorten this to:

        - (IBAction)addLabelText:(UIButton*)sender {
            [self undoTextFieldEdit: @"text"];
        }
    

    as the undoManager invocation is the same in both methods

    Example 2
    Direct keyboard input editing

        #pragma mark - textField delegate methods
    
        - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
        {
            [self.undoManager registerUndoWithTarget:self
                                            selector:@selector(undoTextFieldEdit:)
                                              object:textField.text];
            return YES;
        }
    
        - (BOOL)textFieldShouldReturn:(UITextField *)textField
        {
            //to dismiss the keyboard
            [textField resignFirstResponder];
            return YES;
        }