如何在 UISearchDisplayDelegate 中执行操作之前设置延迟?

How do I set a delay before performing an action in UISearchDisplayDelegate?

我有一个搜索显示控制器,它命中了一个 API 端点。我当前的代码将在每个字符上向 API 端点发出请求。我想做的是仅当用户停止输入 500 毫秒时才发出请求。

代码如下:

在 UISearchDisplayDelegate 中

注意:searchQueue 是一个 NSOperationQueue 对象。

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    [self.searchQueue cancelAllOperations];

    [self.searchQueue addOperationWithBlock:^(){
        [self.AFRequestManager.operationQueue cancelAllOperations];

        NSString *access_token = [[FBSDKAccessToken currentAccessToken] tokenString];

        NSDictionary *params = @{@"name": searchString, @"access_token": access_token };

        NSString *getUrl = [baseUrl stringByAppendingString:@"api/users/search"];
        [self.AFRequestManager GET:getUrl parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
            self.searchedUsers = responseObject;
            [self.searchDisplayController.searchResultsTableView reloadData];

        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Error: %@", error);
        }];
    }];

    return NO;
}

用户输入的每个字符都会调用此委托方法,我想等到用户完成指定名称。

我试过使用 NSTimer 但它很乱。我绝对可以将 searchString 传递给 userInfo。但是,一旦我使 NSTimer 失效,它就不能再使用了。

我试过使用 dispatch_after 但实际上这不起作用,因为每次用户输入一个字符时,搜索都会延迟,但它仍在为用户输入的每个字符发出请求。

我不想过于复杂,但我觉得它应该超级简单而且我遗漏了一些东西。

调用 performSelector:withObject:afterDelay: 怎么样?它对所有 NSObjects 都可用,所以你可以从你的视图控制器中调用它。您可能需要担心的唯一一件事就是没有参加每一个活动并排队等待 2 分钟的延误:

- (void)performSelector:(SEL)aSelector
             withObject:(id)anArgument
             afterDelay:(NSTimeInterval)delay

例子(注:变量名是为了演示我自己编的):

[self performSelector:@selector(callServer:) withObject:params afterDelay:0.5f];

更新:

看来我的回答的第一部分还不够。以下是一些应该可以帮助您得出解决方案的新步骤:

1) 创建一个 NSTimer 属性 以便您可以在任何需要的地方访问它

2) 将您当前在 searchDisplayController:shouldReloadTableForSearchString: 中的逻辑移动到一个新方法中,以便您的计时器可以将其用作其选择器。例如:

- (void)callServerWithDictionary:(NSDictionary*)params;

3) 每当调用 searchDisplayController:shouldReloadTableForSearchString: 时,如果您的计时器实例为 null,请将其实例化并将其时间间隔设置为 500ms,并将其选择器设置为您在步骤 1 中创建的方法。如果计时器是不为空,使其无效并将其设置为一个新的计时器实例,具有与以前相同的 500 毫秒间隔和选择器。

4) 如果您丢失了搜索字符串,则创建一个 属性 来保存它并在每次调用 searchDisplayController:shouldReloadTableForSearchString: 时更新它。尽管我相信您应该可以使用 searchDisplayController.searchBar.text.

之类的内容来访问它

您可以使用 GCD dispatch_after。这是一些例子。

double delayInSeconds = 3.0;

dispatch_time_t buyTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

dispatch_after(buyTime, dispatch_get_main_queue(), ^(void)
{
   //code that will be executed after delay
}

你可以使用这个

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index) {
   // block will be executed 10 times
   // number of launch passes to block
});