我的一个项目中有一个相当复杂的NSTextView子类.我目前正致力于使用内联查找栏(例如Safari,Xcode)进行查找/替换,并希望正确支持撤消/重做以进行替换操作.
我希望Replace All命令支持undo作为单个命令(即如果在文本视图中有8个替换,它也应该同时撤消这8个替换).
我想知道是否存在shouldChangeTextInRanges的对应部分:replaceStrings:我可以在检查后进行替换.我预计会有一个replaceCharactersInRanges:withStrings:或类似的东西,但似乎没有.
我现在能想到的唯一方法是检查对shouldChangeTextInRanges的调用:replaceStrings:首先,然后调用replaceCharactersInRange:withString:整个文本视图范围和新字符串(替换为)第二个论点.
这似乎没必要,如果我不需要,我真的不想替换整个字符串.有任何想法吗?
解决方法
经过一些修修补补,我想我已经搞清楚了.乔希,我用你的建议开始了.我不确定你是否编辑了你的建议或者只是删除了它,但它已经消失了所以我不能在我的答案中引用它.
无论如何,你必须在每次调用replaceCharactersInRange:withString之后移动你要替换的范围:否则会发生不好的事情,因为范围不匹配.这是我最终得到的:
// array of NSValue objects storing an NSRange NSArray *replaceRanges = [self replaceRanges]; NSString *replaceString = [self replaceString]; // array of NSString objects you are going to use for the replace operation,just replaceString repeated [replaceRanges count] times NSArray *replaceStrings = [self replaceStrings]; NSTextView *textView = [self textView]; // the amount we have to shift subequent replace ranges after each call to replaceCharactersInRange:withString: NSInteger locationShift = 0; // check to makes sure the replace can occur if ([textView shouldChangeTextInRanges:replaceRanges replacementStrings:replaceStrings]) { // we want to treat all these replacements as a single replacement for undo purposes [[textView textStorage] beginEditing]; for (NSValue *rangeValue in replaceRanges) { NSRange range = [rangeValue rangeValue]; // replace the range shifted by locationShift with our replaceString [[textView textStorage] replaceCharactersInRange:NSMakeRange(range.location + locationShift,range.length) withString:replaceString]; // update the shift amount,which is the difference between our replaced string length and the original match length locationShift += [replaceString length] - range.length; } // end the grouping operation [[textView textStorage] endEditing]; }
这非常有用并支持按预期方式撤消,撤消此操作会导致所有替换一次撤消.
无论如何,感谢Josh,因为他的回答让我指出了正确的方向.