0

我正在尝试使用 NSLinguisticTagger 来监视 NSTextStorage 的内容并根据用户键入的内容提供一些上下文信息。为此,我有一个 OverlayManager 对象,它连接了这种关系:

-(void) setView:(NSTextView*) view {
    _view = view;
    _layout = view.layoutManager;
    _storage = view.layoutManager.textStorage; //get the TextStorage from the view
    [_tagger setString:_storage.string]; //pull the string out, this grabs the mutable version
    [self registerForNotificationsOn:self->_storage]; //subscribe to the willProcessEditing notification
}

当编辑发生时,我确保捕获它并通知标记器(是的,我知道我与成员访问不一致,我对 Obj-C 生疏了,我稍后会修复它):

- (void) textStorageWillProcessEditing:(NSNotification*) notification{
    if ([self->_storage editedMask] & NSTextStorageEditedCharacters) {
        NSRange editedRange = [self->_storage editedRange];
        NSUInteger delta = [self->_storage changeInLength];
        [_tagger stringEditedInRange:editedRange changeInLength:delta]; //should notify the tagger of the changes- if I replace this line with [_tagger setString:[_storage string]] it works, but gobbles CPU as it retags the entire string
        [self highlightEdits:self];
    }
}

highlightEdits 消息将作业委托给“覆盖”对象池。每个都包含一个与此类似的代码块:

[tagger enumerateTagsInRange:range scheme:NSLinguisticTagSchemeLexicalClass options:0 usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
            if (tag == PartOfSpeech) {
                [self applyHighlightToRange:tokenRange onStorage:storage];
            }
        }];

这就是问题所在 - enumerateTagsInRange 方法崩溃并显示一条消息:

2014-06-04 10:07:19.692 WritersEditor[40191:303] NSMutableRLEArray     replaceObjectsInRange:withObject:length:: Out of bounds

如果我不链接到底层字符串的可变副本而是执行 a ,则不会发生此问题[[_storage string] copy],但显然我不想在每次要进行标记时都复制整个后备存储。这一切都应该发生在主运行循环中,所以我认为这不是线程问题。我枚举标签的 NSRange 存在于 NSTextStorageNSLinguisticTagger 的字符串视图中。applyHighlightToRange 调用甚至不会向字符串添加属性,因为它甚至在到达该行之前就崩溃了。

我试图围绕该问题构建一个测试用例,但在这些情况下无法复制它:

- (void) testEdit
{
    NSAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Quickly, this is a test."];
    text = [[NSTextStorage alloc] initWithAttributedString:str];

    NSArray* schemes = [NSLinguisticTagger availableTagSchemesForLanguage:@"en"];
    tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:schemes options:0];
    [tagger setString:[text string]];

    [text beginEditing];
    [[text mutableString] appendString:@"T"];
    NSRange edited = [text editedRange];
    NSUInteger length = [text changeInLength];
    [text endEditing];

    [tagger stringEditedInRange:edited changeInLength:length];
    [tagger enumerateTagsInRange:edited scheme:NSLinguisticTagSchemeLexicalClass options:0 usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
        //doesn't matter, this should crash
    }];
}

该代码不会崩溃。

4

0 回答 0