NSTextView replaceCharactersInRange:withString:shouldChangeTextInRanges:replacementStrings:

我的一个项目中有一个相当复杂的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,因为他的回答让我指出了正确的方向。     
我很惊讶撤消,因为没有自动分组。但是,您可以手动撤消分组;你必须自己设置反向动作。希望这会指出你正确的方向:
- (BOOL)shouldChangeTextInRanges:(NSArray *)affectedRanges replacementStrings:(NSArray *)replacementStrings {

    NSUndoManager * undoMan = [self undoManager];
    [undoMan beginUndoGrouping];
    NSEnumerator stringEnumerator = [replacementStrings objectEnumerator];
    for( NSRange thisRange in affectedRanges ){
        NSString * thisString = [stringEnumerator nextObject];
        NSTextStorage * textStore = [self textStorage];
        [[undoMan prepareWithInvocationTarget:textStore] 
                 replaceCharactersInRange:thisRange 
                               withString:[textStore attributedSubstringFromRange:thisRange]];

        [textStore replaceCharactersInRange:thisRange withString:thisString];
    }
    [undoMan endUndoGrouping];
    [undoMan setActionName:@"Replace All"];

    return NO; // because we just did it by hand
}
    

要回复问题请先登录注册