我有一个带有格式工具栏的UITextView
。按下“粗体”按钮后,它会更改文本/选择并使用文本视图NSUndoManager
注册操作。
当您尝试撤消时,会一遍又一遍地调用restoreText:
,直到您杀死该应用
一些示例代码:
- (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];
}
控制台:
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
我在[self.textView.undoManager isUndoing]
上注册调用之前尝试检查restoreText:withRange:
,但崩溃了:
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
'
此代码适用于iOS5,但已停止在iOS6上运行。我已经向Apple提交了一个错误,但我不确定我做错了什么
答案 0 :(得分:0)
即使是简单撤消,我的UITextView实例也会发生同样的事情。这必定是一个错误,这意味着您自己不能再对UITextView实现撤消功能。 我想知道是否有人在iOS6 UITextView上成功实现了撤消功能...
或者,我决定使用replaceRange:withText :( TextInput Protocol)代替在UITextView上实现我的撤消功能。至少你可以用该方法撤消替换文本。您不需要自己注册撤消操作。该方法自动完成。
答案 1 :(得分:0)
我遇到了同样的问题,发现访问textView的文本会导致奇怪的行为,比如重复调用方法和崩溃。
textView.text=@"" //this crashes
这可以通过user1283865建议使用replaceRange:withText:
来解决,
如果要自定义要处理撤消/重做的操作,可以注册操作,但跳过修改文本的部分,因为replaceRange:withText:
已经处理了它。
例如,如果我想创建一个清除文本功能,清除textView中的文本以及自定义消息对象,则在用户撤消操作时将其恢复:
-(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.
}