UITextView and NSUndoManager don’t work really well on iOS6, directly modifying textView’s text causes crash.
For example, the following code doesn’t work as expected.
-(void) clearEditText {
//Register undo
[[textView.undoManager prepareWithInvocationTarget:self] undoClearEditText:[textView.text retain] withMessage:[self.message retain]];
//message is retained because undo manager will not retain, it will be released when user undo.
// Clear text field
textView.text=@"";
self.message = /*new message*/;
}
-(void) undoClearEditText:(NSString*)restoreText withMessage:(Message*)restoreMessage {
//Register redo
[[textView.undoManager prepareWithInvocationTarget:self] undoClearEditText:[textView.text retain] withMessage:[self.message retain]];
self.message = restoreMessage;
textView.text=restoreText;
[restoreMessage release];
[restoreText release];
//message is released because it is retained when it is added to undo manager.
}
After trial and error, it seems that text changes are handled by undoManager and I shouldn’t access it directly.
Instead UITextView’s replaceRange:withText: should be used, it handles undo and redo automatically, so no extra work is needed if you only want to replace text.
For customized undo/redo action, it can be done like this:
I am setting a new message object when user clears texts, and put that object back when the user undo the clear action, redo works as well.
-(void) clearEditText {
//Register undo
[[textView.undoManager prepareWithInvocationTarget:self] undoClearEditTextWithMessage:[self.message retain]];
//message is retained because undo manager will not retain, it will be released when user undo.
// Clear text field
UITextPosition *beginning = textView.beginningOfDocument;
UITextPosition *end= textView.endOfDocument;
UITextRange *textRange = [textView textRangeFromPosition:beginning toPosition:end];
[textView replaceRange:textRange withText:@""];
self.message = /*new message*/;
}
-(void) undoClearEditTextWithMessage:(Message*)restoreMessage {
//Register redo
[[textView.undoManager prepareWithInvocationTarget:self] undoClearEditTextWithMessage:[self.message retain]];
self.message = restoreMessage;
[restoreMessage release];
//message is released because it is retained when it is added to undo manager.
}
Text changes don’t need to be handled, replaceRange:withText: will do it automatically.