I have a UITextView
with a formatting toolbar. After I press the "bold" button, it changes the text/selection and registers the operation with the text view's NSUndoManager
.
When you try to undo, restoreText:
is called over and over until you kill the app
Some sample code:
- (void)bold {
NSRange range = self.textView.selectedRange;
NSRange oldRange = range;
NSString *oldText = self.textView.text;
NSString *selection = [self.textView.text substringWithRange:range];
self.textView.scrollEnabled = NO;
self.textView.text = [self.textView.text stringByReplacingCharactersInRange:range
withString:[NSString stringWithFormat:@"<b>%@</b>", selection]];
self.textView.scrollEnabled = YES;
if (range.length == 0) { // If nothing was selected
range.location += 3; // Place selection between tags
} else {
range.location += range.length + 7; // Place selection after tag
range.length = 0;
}
self.textView.selectedRange = range;
[[self.textView.undoManager prepareWithInvocationTarget:self] restoreText:oldText withRange:oldRange];
[self.textView.undoManager setActionName:@"bold"];
}
- (void)restoreText:(NSString *)text withRange:(NSRange)range {
NSLog(@"restoreText:%@ %@",text, [NSNumber numberWithBool:[self.textView.undoManager isUndoing]]);
NSString *oldText = self.textView.text;
NSRange oldRange = self.textView.selectedRange;
self.textView.scrollEnabled = NO;
self.textView.text = text;
self.textView.scrollEnabled = YES;
self.textView.selectedRange = range;
[[self.textView.undoManager prepareWithInvocationTarget:self] restoreText:oldText withRange:oldRange];
}
And the console:
2012-10-04 18:10:14.207 undotest[8861:c07] restoreText: 1
2012-10-04 18:10:14.633 undotest[8861:c07] restoreText:<b></b> 0
2012-10-04 18:10:15.117 undotest[8861:c07] restoreText: 0
2012-10-04 18:10:15.589 undotest[8861:c07] restoreText:<b></b> 0
2012-10-04 18:10:16.017 undotest[8861:c07] restoreText: 0
2012-10-04 18:10:16.557 undotest[8861:c07] restoreText:<b></b> 0
I've tried checking for [self.textView.undoManager isUndoing]
before registering the invocation on restoreText:withRange:
, but that crashes:
2012-10-04 18:10:49.297 undotest[8904:c07] restoreText: 1
2012-10-04 18:10:53.412 undotest[8904:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '_endUndoGroupRemovingIfEmpty:: WebThreadSafeUndoManager 0x76551e0 is in invalid state, endUndoGrouping called with no matching begin
'
This code was working on iOS5 but stopped working on iOS6. I've filed a bug with Apple, but I'm not sure if I'm doing something wrong