【问题标题】:NSUndoManager calls my "restore" method repeatedlyNSUndoManager 反复调用我的“恢复”方法
【发布时间】:2012-10-04 16:13:40
【问题描述】:

我有一个带有格式工具栏的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

我尝试在restoreText:withRange: 上注册调用之前检查[self.textView.undoManager isUndoing],但这会崩溃:

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 提交了一个错误,但我不确定我是否做错了什么

【问题讨论】:

    标签: objective-c ios uitextview ios6 nsundomanager


    【解决方案1】:

    即使是简单的撤消,我的 UITextView 实例也会发生同样的事情。这一定是个bug,意味着你的UITextView不能再自己实现撤消功能了。 不知道有没有人在 iOS6 UITextView 上成功实现了撤销功能...

    另外,我决定使用 replaceRange:withText:(TextInput 协议)来实现我在 UITextView 上的撤消功能。至少您可以撤消使用该方法替换文本。您不需要自己为此注册撤消操作。该方法会自动执行。

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,发现访问textView的文本会导致奇怪的行为,比如重复调用方法并崩溃。

      textView.text=@"" //this crashes
      

      这可以通过 user1263865 的建议使用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.
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-31
        • 1970-01-01
        • 2021-05-31
        • 2020-09-13
        • 2022-12-30
        • 2011-05-04
        • 1970-01-01
        • 2013-02-20
        相关资源
        最近更新 更多