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
Cocoa NSTextFinder+;以编程方式更改NSTextView中的文本_Cocoa_Nstextview - Fatal编程技术网

Cocoa NSTextFinder+;以编程方式更改NSTextView中的文本

Cocoa NSTextFinder+;以编程方式更改NSTextView中的文本,cocoa,nstextview,Cocoa,Nstextview,我有一个要使用查找栏的NSTextView。文本是可选择的,但不可编辑。我以编程方式更改文本视图中的文本 当NSTextFinder在文本更改后尝试选择下一个匹配项时,此设置可能会崩溃。对于增量匹配,NSTextFinder似乎保留了过时的范围 我尝试了几种修改文本的方法: [textView setString:@""]; 或 或 仅replaceTextStorage:调用-[NSTextFinder noteClientStringWillChange]。上述操作均未调用-[NSText

我有一个要使用查找栏的NSTextView。文本是可选择的,但不可编辑。我以编程方式更改文本视图中的文本

当NSTextFinder在文本更改后尝试选择下一个匹配项时,此设置可能会崩溃。对于增量匹配,NSTextFinder似乎保留了过时的范围

我尝试了几种修改文本的方法:

[textView setString:@""];

仅replaceTextStorage:调用-[NSTextFinder noteClientStringWillChange]。上述操作均未调用-[NSTextFinder cancelFindIndicator]

即使通知了NSTextFinder有关文本更改的信息,它也可能在查找下一个(command-G)时崩溃

我还尝试创建自己的NSTextFinder实例作为。尽管NSTextView没有实现NSTextFinderClient协议,但其工作原理和失败方式与没有NSTextFinder实例时相同


将NSTextFinder与NSTextView一起使用的正确方法是什么?

我的应用程序中的文本视图也有同样的问题,更令人恼火的是,您在internet上找到的所有“解决方案”要么不正确,要么至少不完整。这就是我的贡献

在NSTextView中设置
textView.useFindBar=YES
时,此文本视图在内部创建一个NSTextFinder,并将搜索/替换命令转发给它。不幸的是,NSTextView似乎无法正确处理您以编程方式对其关联的NSTextStorage所做的更改,从而导致您提到的崩溃

如果要更改此行为,仅创建专用的NSTextFinder是不够的:还需要避免文本视图使用其默认文本查找器,否则会发生冲突,并且新的文本查找器不会有多大用处

要执行此操作,必须将NSTextView子类化:

@interface MyTextView : NSTextView

- (void) resetTextFinder; // A method to reset the view's text finder when you change the text storage

@end
在文本视图中,您必须覆盖用于控制文本查找器的响应程序方法:

@interface MyTextView ()  <NSTextFinderClient>
{
    NSTextFinder* _textFinder; // define your own text finder
}

@property (readonly) NSTextFinder* textFinder;

@end

@implementation MyTextView

// Text finder command validation (could also be done in method validateUserInterfaceItem: if you prefer) 

- (BOOL) validateMenuItem:(NSMenuItem *)menuItem
{
    BOOL isValidItem = NO;

    if (menuItem.action == @selector(performTextFinderAction:)) {
        isValidItem = [self.textFinder validateAction:menuItem.tag];
    }
    // validate other menu items if needed
    // ...
    // and don't forget to call the superclass
    else {
        isValidItem = [super validateMenuItem:menuItem];
    }

    return isValidItem;
}

// Text Finder

- (NSTextFinder*) textFinder
{
    // Create the text finder on demand
    if (_textFinder == nil) {
        _textFinder = [[NSTextFinder alloc] init];
        _textFinder.client = self;
        _textFinder.findBarContainer = [self enclosingScrollView];
        _textFinder.incrementalSearchingEnabled = YES;
        _textFinder.incrementalSearchingShouldDimContentView = YES;
    }

    return _textFinder;
}

- (void) resetTextFinder
{
    if  (_textFinder != nil) {
        // Hide the text finder 
        [_textFinder cancelFindIndicator];
        [_textFinder performAction:NSTextFinderActionHideFindInterface];

        // Clear its client and container properties
        _textFinder.client = nil;
        _textFinder.findBarContainer = nil;

        // And delete it
        _textFinder = nil;
    }
}

// This is where the commands are actually sent to the text finder
- (void) performTextFinderAction:(id<NSValidatedUserInterfaceItem>)sender
{
    [self.textFinder performAction:sender.tag];
}

@end
@接口MyTextView()
{
NSTextFinder*\u textFinder;//定义您自己的文本查找器
}
@属性(只读)NSTextFinder*textFinder;
@结束
@MyTextView的实现
//文本查找器命令验证(也可以在validateUserInterfaceItem方法中完成:如果您愿意)
-(BOOL)validateNuItem:(NSMenuItem*)menuItem
{
BOOL isValidItem=否;
if(menuItem.action=@选择器(performTextFinderAction:){
isValidItem=[self.textFinder validateAction:menuItem.tag];
}
//如果需要,验证其他菜单项
// ...
//别忘了调用超类
否则{
isValidItem=[super-validateNuItem:menuiItem];
}
返回有效期;
}
//文本查找器
-(NSTextFinder*)textFinder
{
//按需创建文本查找器
如果(_textFinder==nil){
_textFinder=[[NSTextFinder alloc]init];
_textFinder.client=self;
_textFinder.findBarContainer=[自封闭CrollView];
_textFinder.incrementalSearchingEnabled=是;
_textFinder.incrementalSearchingShouldDimContentView=YES;
}
返回文本查找器;
}
-(无效)重置文本查找器
{
如果(_textFinder!=nil){
//隐藏文本查找器
[_textfindercancelfindIndicator];
[\u textFinder性能:NSTextFinderActionHideFindInterface];
//清除其客户端和容器属性
_textFinder.client=nil;
_textFinder.findBarContainer=nil;
//然后删除它
_textFinder=nil;
}
}
//这是命令实际发送到文本查找器的位置
-(无效)performTextFinderAction:(id)发件人
{
[self.textFinder性能:sender.tag];
}
@结束
在文本视图中,您仍然需要将属性
usesFindBar
incrementalsearchingenerable
设置为
YES

在更改视图的文本存储(或文本存储内容)之前,只需调用
[myTextView resetTextFinder]
下次搜索时为新内容重新创建全新的文本查找器


如果您想了解更多有关NSTextFinder的信息,我所看到的最好的文档是在

中。我提出的解决方案似乎与@jlj提供的解决方案非常相似。在这两种解决方案中,NSTextView都用作NSTextFinder的客户端

看起来主要的区别在于我没有隐藏文本更改的查找栏。我还保留了我的NSTextFinder实例。为此,我需要调用
[textFinder noteClientStringWillChange]

更改文本:

NSTextView *textView = self.textView;
NSTextFinder *textFinder = self.textFinder;

[textFinder cancelFindIndicator];
[textFinder noteClientStringWillChange];

[textView setString:@"New text"];
视图控制器代码的其余部分如下所示:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSTextFinder *textFinder = [[NSTextFinder alloc] init];

    [textFinder setClient:(id < NSTextFinderClient >)textView];
    [textFinder setFindBarContainer:[textView enclosingScrollView]];

    [textView setUsesFindBar:YES];
    [textView setIncrementalSearchingEnabled:YES];

    self.textFinder = textFinder;
}

- (void)viewWillDisappear
{
    NSTextFinder *textFinder = self.textFinder;

    [textFinder cancelFindIndicator];

    [super viewWillDisappear];
}

- (id)supplementalTargetForAction:(SEL)action sender:(id)sender
{
    id target = [super supplementalTargetForAction:action sender:sender];

    if (target != nil) {
        return target;
    }

    if (action == @selector(performTextFinderAction:)) {
        target = self.textView;

        if (![target respondsToSelector:action]) {
            target = [target supplementalTargetForAction:action sender:sender];
        }

        if ((target != self) && [target respondsToSelector:action]) {
            return target;
        }
    }

    return nil;
}
-(void)viewDidLoad
{
[超级视图下载];
NSTextFinder*textFinder=[[NSTextFinder alloc]init];
[textFinder setClient:(id)textView];
[textFinder setFindBarContainer:[textView EnclosuringScrollView]];
[textView setUsesFindBar:是];
[textView SetIncrementalSearchEnabled:是];
self.textFinder=textFinder;
}
-(无效)视图将消失
{
NSTextFinder*textFinder=self.textFinder;
[textFinder cancelFindIndicator];
[超级视图将消失];
}
-(id)补充目标行动:(SEL)行动发送者:(id)发送者
{
id target=[super-supplementalTargetForAction:action-sender:sender];
如果(目标!=零){
回报目标;
}
if(action=@选择器(performTextFinderAction:){
target=self.textView;
如果(![target respondsToSelector:action]){
target=[target-supplementalTargetForAction:action-sender:sender];
}
if((target!=self)&&[target respondsToSelector:action]){
回报目标;
}
}
返回零;
}

谢谢!我忘记了这个问题。我已经想出了一个可行的解决方案,但忘了在这里发布。我将发布我自己的代码作为答案。无法在注释中获取可读的格式。
NSTextView *textView = self.textView;
NSTextFinder *textFinder = self.textFinder;

[textFinder cancelFindIndicator];
[textFinder noteClientStringWillChange];

[textView setString:@"New text"];
- (void)viewDidLoad
{
    [super viewDidLoad];

    NSTextFinder *textFinder = [[NSTextFinder alloc] init];

    [textFinder setClient:(id < NSTextFinderClient >)textView];
    [textFinder setFindBarContainer:[textView enclosingScrollView]];

    [textView setUsesFindBar:YES];
    [textView setIncrementalSearchingEnabled:YES];

    self.textFinder = textFinder;
}

- (void)viewWillDisappear
{
    NSTextFinder *textFinder = self.textFinder;

    [textFinder cancelFindIndicator];

    [super viewWillDisappear];
}

- (id)supplementalTargetForAction:(SEL)action sender:(id)sender
{
    id target = [super supplementalTargetForAction:action sender:sender];

    if (target != nil) {
        return target;
    }

    if (action == @selector(performTextFinderAction:)) {
        target = self.textView;

        if (![target respondsToSelector:action]) {
            target = [target supplementalTargetForAction:action sender:sender];
        }

        if ((target != self) && [target respondsToSelector:action]) {
            return target;
        }
    }

    return nil;
}