我有一个非常简单的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
。
答案 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秒),以允许用户在触发前完成有意义的搜索字词