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

问题描述:

我有一个搜索显示控制器,它击中一个API端点。我当前的代码将向每个字符上的API端点发出请求。我想要做的只是当用户停止输入500毫秒时才发出请求。如何在UISearchDisplayDelegate中执行操作之前设置延迟?

下面是代码:

在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,但实际上这并不起作用,因为每次用户输入字符时,搜索都会延迟,但它仍在为用户输入的每个字符发出请求。

我不想过度复杂,但我觉得它应该是超级简单,我错过了一些东西。

+0

您可以使用用户信息中的NSTimer到搜索字符串传递到选择,或使用dispatch_after,创建一个新的请求,当用户键入一个字母和取消任何延迟请求。无论哪种方式,请求都是堆叠的,需要在某个时候取消。 – Thomas 2015-03-30 19:10:16

+0

我确实尝试过dispatch_after,但仍然会排队3个延迟500ms的请求。我只想要1个请求,除非用户不输入500ms的字符。 – okysabeni 2015-03-30 20:17:55

怎么样调用performSelector:withObject:afterDelay:?它可用于所有NSObject,因此您可以从视图控制器调用它。

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

例子(注:我做了变量名称为示范的目的):

你可能会担心没有采取在每一个事件和排队值得延迟2分钟的唯一的事情
[self performSelector:@selector(callServer:) withObject:params afterDelay:0.5f]; 

UPDATE:

看来好像我的回答的第一部分是不够的。这里有一些新的步骤,将帮助你得出一个解决方案:

1)创建一个NSTimer属性,这样你需要的地方

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

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

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

4)如果丢失搜索字符串,则创建一个属性来保存它,并在每次调用searchDisplayController:shouldReloadTableForSearchString:时更新它。虽然我相信你应该可以用searchDisplayController.searchBar.text之类的东西来访问它。

+0

这段代码在我的原始代码示例中将被调用? – okysabeni 2015-03-30 20:16:28

+0

你可以在下面放置这个[self.searchQueue cancelAllOperations];然后将addOperationWithBlock逻辑封装在由我的示例中提供的代码行调用的单独方法中。唯一棘手的是确保你传递所有正确的变量/适当的对象。 – 2015-03-30 20:21:22

+0

这仍然会为用户键入的每个字符发出请求。我只想在用户停止输入500毫秒时发出请求。 – okysabeni 2015-03-30 20:25:51

您可以使用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 
}); 
+0

我确实尝试过,但仍然会排队3次延迟的请求。我想要的只是做1个请求,除非用户等待超过500毫秒。 – okysabeni 2015-03-30 20:17:03

+0

和dispatch_apply呢?我已经编辑了答案检查。 – SergStav 2015-03-30 20:20:10

+0

您是否尝试过dispatch_apply? – SergStav 2015-03-30 21:06:45