NSSearchField两次清除调用操作

时间:2018-08-14 04:43:17

标签: objective-c xcode macos cocoa

我有一个非常简单的NSSearchField设置。我希望每当用户键入一个字符时,如果在较短的时间内,用户不再输入任何内容,它将自动调用action

我将NSSearchField's action从界面构建器连接到其他一些对象中的IBAction

我面临的问题:由于某种原因,当用户单击关闭按钮或按退出键以清除搜索字段时,action被触发两次。有谁知道如何避免action两次被打通?

#import "ViewController.h"

@implementation ViewController

- (IBAction) searchingStarts:(id)sender
{
    printf("action is triggered\n");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}


- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
    // Update the view, if already loaded.
}

@end

您可以简单地将NSSearchField拖到情节提要中并将其action链接到searchingStarts

这是我的设置:https://github.com/YLiLarry/nssearchfield-bug

4 个答案:

答案 0 :(得分:1)

我认为您应该使用委托来避免这种情况。

- (void)searchFieldDidEndSearching:(NSSearchField *)sender

答案 1 :(得分:0)

该操作由按钮触发,并且因为值更改。如果该操作无法处理多次调用,请设置搜索字段的委托并实现NSSearchFieldDelegate方法

- (void)searchFieldDidStartSearching:(NSSearchField *)sender;

- (void)searchFieldDidEndSearching:(NSSearchField *)sender;

答案 2 :(得分:0)

对我有用的快速版本:

在类中实施NSSearchFieldDelegate方法:

extension MyClassName: NSSearchFieldDelegate {

    func searchFieldDidStartSearching(_ sender: NSSearchField) {
        disableFilter = false
    }

    func searchFieldDidEndSearching(_ sender: NSSearchField) {
        disableFilter = false
        // TODO: perform cleanup operations if necessary...
    }
}

disableFilter 作为变量添加到您的课程中:

class MyClassName: ViewController  {
...
/**
 Used to determine if the cancel button of the NSSearchField was pressed and 
 take steps to avoid the NSSearchField from sending action messages.
*/
var disableFilter: Bool = false
...
}

创建搜索功能:

@objc 
func search(_ sender: Any) {
    if disableFilter {
        return
    }

    // TODO: add your search implementation here...
}

如果在IB中完成操作,则将操作分配给搜索字段对象:

override func viewDidLoad() {
    searchField.action = #selector(search(_:))
}

答案 3 :(得分:0)

在我的文档视图控制器实际上分派给子视图控制器的情况下,这是一种用绅士语言表达的公式-我有一个模块化的窗口结构,由许多选项卡和拆分视图容器组成。

@implementation MyDocViewController(search)
#pragma mark - NSSearchFieldDelegate

- (void) searchFieldDidStartSearching: (NSSearchField*) sender
{
    for (NSViewController* aController in self.childViewControllers)
    {
        if ([aController conformsToProtocol: @protocol(NSSearchFieldDelegate)])
        {
            [(NSViewController<NSSearchFieldDelegate>*) aController searchFieldDidStartSearching: sender];
        }
    }
}

- (void) searchFieldDidEndSearching: (NSSearchField*) sender
{
     for (NSViewController* aController in self.childViewControllers)
    {
        if ([aController conformsToProtocol: @protocol(NSSearchFieldDelegate)])
        {
            [(NSViewController<NSSearchFieldDelegate>*) aController searchFieldDidEndSearching: sender];
        }
    }
}
@end

在情节提要中,搜索字段委托链接到上述文档视图控制器。无法直接通过情节提要板访问窗口中组装的子组件,这就是为什么我将其分发给子视图控制器。

在一个子控制器中,将有相同的协议声明,并且将完成最后的搜索操作。 请注意,如果只有一个子视图控制器实际上将自身设置为搜索字段的目标,则此方法有效。

@implementation MyChildViewController(search)
#pragma mark - NSSearchFieldDelegate

- (IBAction) onSearch: (NSSearchField*) sender
{
    NSLog(@"Filtering on %@", sender.stringValue);

    [self rebuildNodes: sender.stringValue];
}

- (void) searchFieldDidStartSearching: (NSSearchField*) sender
{
    [sender setTarget: self];
    [sender setAction: @selector(onSearch:)];
    [self rebuildNodes: sender.stringValue];
}

- (void) searchFieldDidEndSearching: (NSSearchField*) sender
{
    [sender setTarget: nil];
    [sender setAction: nil];
    [self rebuildNodes: nil];
}
@end

@end

就我而言,搜索速度很快。在基于CoreData的对象存储文档结构中,搜索完成后将以毫秒为单位突出显示绘制的图形,因此我可以实时搜索并在用户输入新搜索词时重置。

如果您的搜索周期较长,则最好在接收到新的搜索字词时使先前的搜索计时器无效,并启动一个新的计时器(例如1秒),以允许用户在触发前完成有意义的搜索字词

Storyboard Settings