Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macos 修改NSTextStorage会导致插入点移动到行的末尾_Macos_Cocoa_Nstextview_Nstextstorage - Fatal编程技术网

Macos 修改NSTextStorage会导致插入点移动到行的末尾

Macos 修改NSTextStorage会导致插入点移动到行的末尾,macos,cocoa,nstextview,nstextstorage,Macos,Cocoa,Nstextview,Nstextstorage,我有一个NSTextView子类充当它的NSTextStorage委托。我试着做两件事: 以某种方式突出显示文本 评估文本,然后将答案附加到textview 我用两种不同的方法来实现这一点,这两种方法都由-(void)textStorageWillProcessEditing:(NSNotification*)notification委托回调调用 我可以很好地突出显示语法,但是在添加答案时,插入点会跳到行的末尾,我真的不知道为什么。我的求值方法如下所示: NSString *result = .

我有一个
NSTextView
子类充当它的
NSTextStorage
委托。我试着做两件事:

  • 以某种方式突出显示文本
  • 评估文本,然后将答案附加到textview
  • 我用两种不同的方法来实现这一点,这两种方法都由
    -(void)textStorageWillProcessEditing:(NSNotification*)notification
    委托回调调用

    我可以很好地突出显示语法,但是在添加答案时,插入点会跳到行的末尾,我真的不知道为什么。我的求值方法如下所示:

    NSString *result = ..;
    NSRange lineRange = [[textStorage string] lineRangeForRange:[self selectedRange]];
    NSString *line = [[textStorage string] substringWithRange:lineRange];
    line = [self appendResult:result toLine:line]; // appends the answer
    
    [textStorage replaceCharactersInRange:lineRange withString:line];
    
    - (void)insertText:(id)insertString {
        [super insertText:insertString];
        NSRange selectedRange = [self selectedRange];
        [self doEvaluationAndAppendResult];
        [self setSelectedRange:selectedRange];
    }
    
    - (void)processEditing {
        //Process self.editedRange and apply styles first
        [super processEditing];
    }
    
    这样做将很好地附加我的结果,但问题是,正如前面提到的,插入点跳到了末尾

    我试过:

  • 将上述调用包装在
    [textStorage beginEditing]
    -endEditing
  • 在更改文本存储之前保存选择范围(即插入点),以便以后可以重置它,但不能使用骰子

  • 我这样做对吗?我正试图以最不粗俗的方式来做这件事,我也不确定这是否是进行解析/突出显示的理想场所。医生让我相信了这一点,但也许这是错的。

    很简单!我最后把这个问题分成两部分。由于
    textStorage
    delegate回调,我仍然会突出显示语法,但现在我会在其他地方进行计算和追加

    我最终覆盖了
    -insertText:
    -deleteBackwards:
    (我可能也希望对
    -deleteForwards:
    执行同样的操作)。这两个覆盖看起来如下所示:

    NSString *result = ..;
    NSRange lineRange = [[textStorage string] lineRangeForRange:[self selectedRange]];
    NSString *line = [[textStorage string] substringWithRange:lineRange];
    line = [self appendResult:result toLine:line]; // appends the answer
    
    [textStorage replaceCharactersInRange:lineRange withString:line];
    
    - (void)insertText:(id)insertString {
        [super insertText:insertString];
        NSRange selectedRange = [self selectedRange];
        [self doEvaluationAndAppendResult];
        [self setSelectedRange:selectedRange];
    }
    
    - (void)processEditing {
        //Process self.editedRange and apply styles first
        [super processEditing];
    }
    

    最后我不得不在这里手动重置插入点。我仍然很想弄清楚为什么这是必要的,但至少这感觉不像是一个黑客。

    我知道这个问题早就得到了回答,但我也有同样的问题。在我的
    NSTextStorage
    子类中,我执行了以下操作:

    NSString *result = ..;
    NSRange lineRange = [[textStorage string] lineRangeForRange:[self selectedRange]];
    NSString *line = [[textStorage string] substringWithRange:lineRange];
    line = [self appendResult:result toLine:line]; // appends the answer
    
    [textStorage replaceCharactersInRange:lineRange withString:line];
    
    - (void)insertText:(id)insertString {
        [super insertText:insertString];
        NSRange selectedRange = [self selectedRange];
        [self doEvaluationAndAppendResult];
        [self setSelectedRange:selectedRange];
    }
    
    - (void)processEditing {
        //Process self.editedRange and apply styles first
        [super processEditing];
    }
    
    但是,正确的做法是:

    - (void)processEditing {
        [super processEditing];
        //Process self.editedRange and apply styles after calling superclass method
    }
    
    插入点移动的原因 令人惊讶的是,我从来没有找到一个实际的解释来解释为什么这些建议有效(或无效)

    深入研究,插入点移动的原因是:
    .editedCharacters
    NSTextStorageEditedCharacters
    ,在ObjC中)影响插入点在
    NSLayoutManager.processEditing(from:editedMask:…)
    中的位置

    如果仅发送
    .editedAttribute
    /
    NSTextStorageeditedAttribute
    ,则插入点将不会被触摸。这就是您在突出显示“仅更改属性”时要实现的目标

    为什么高亮显示会影响插入点 此处突出显示的问题是
    NSTextStorage
    在单个处理运行期间收集所有
    编辑的
    调用,并组合范围,从用户编辑的更改开始(例如键入时的插入),然后将此范围与addAttributes报告的所有范围合并(u:range:)
    。这将导致一个
    NSLayoutManager.processEditing(from:editedMask:…)
    调用,调用的
    editedMask
    同时包含
    [.editedCharacters、.editedAttribute]

    因此,您希望为突出显示的范围发送
    .editedAttribute
    ,但最终与
    .editedCharacters
    形成联合。该并集将插入点WAAAAY移动到超出其应移动的位置

    更改
    processEditing
    中的顺序以调用super first works,因为版面管理器将收到已完成编辑的通知。但这种方法在某些边缘情况下仍然会中断,导致在键入非常大的段落时布局无效或滚动视图抖动

    顺便说一句,我也是

    在布局真正完成后挂接回调,以触发高亮显示,而不是
    processEditing
    基于Cocoa框架固有的原因,唯一有效的解决方案是以独占方式从
    textDidChange(:)
    执行高亮显示,即在布局处理真正完成之后。订阅
    NSTextDidChangeNotification
    也同样有效

    缺点:对于底层字符串的编程更改,您必须触发高亮显示过程,因为这些过程不会调用
    textDidChange(u:)
    回调


    如果你想更多地了解问题的根源,我会在一篇更长的博文中提供更多我的研究、不同的方法和解决方案的细节,以供参考。这篇文章本身仍然是一个独立的解决方案:

    什么是lineForRange,我在文档中找不到该方法?如果您是指lineRangeForRange,那么这可能是您的问题。你是想附加到行的末尾,还是选择的结尾?我问题的第二部分怎么样?不清楚您试图将文本附加到何处。当你说插入点移到行尾时,你的意思是在插入之后还是之前?对不起,是的,我正在尝试附加到行尾。再一次,你只回答了我一半的问题。到底是什么问题?文本替换是否正确,但插入点是否移到了末尾(您是指文本的结尾还是仅指行)?或者,替换文本是否位于错误的位置?问题是:
    这样做将附加我的结果,但问题是,如上所述,插入点跳到了末尾。
    谢谢,这解决了我的问题。如果使用NSTextStorageDelegate时遇到此问题,请使用textStorageDidProcessEditing:而不是textStorageWillProcessEditing:。不过,请务必阅读文档中关于将文本存储保留在不一致状态的警告。提醒:虽然这确实有效,但您必须小心不要使用