我正在尝试使用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消息将作业委托给“Overlay”对象池。每个代码都包含一个与此类似的代码块:
[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
如果我没有链接到底层字符串的可变副本而是执行[[_storage string] copy]
,那么不会发生 ,但显然我不想复制每次我想做标记时,整个后备存储。这一切都应该在主运行循环中发生,所以我不认为这是一个线程问题。我正在枚举标签的NSRange存在于NSLinguisticTagger的字符串视图中的NSTextStorage 和中。这甚至不是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
}];
}
该代码不会崩溃。