¿Cómo detectar una pausa en la entrada para UISearchBar / UITextField?

Tengo el siguiente código UISearchbar:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; NSString* endpoint =[NSString stringWithFormat:@"http://www.someurl/", [searchText stringByReplacingOccurrencesOfString:@" " withString:@"+"]]; NSURL* url = [NSURL URLWithString:endpoint]; NSURLRequest* request = [NSURLRequest requestWithURL:url]; GTMHTTPFetcher* myFetcher = [GTMHTTPFetcher fetcherWithRequest:request]; [myFetcher beginFetchWithDelegate:self didFinishSelector:@selector(searchResultsFetcher:finishedWithData:error:)]; } 

Deseo enviar esta solicitud después de una pausa en la entrada y reiniciar el temporizador cada vez que se golpea un personaje. ¿Cómo puedo hacer esto?

No tiene que usar NSTimer.

 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(request) object:nil]; //..... [self performSelector:@selector(request) withObject:nil afterDelay:yourpausetime]; } 

En el método textDidChange crea un NSTimer, digamos 2 segundos vale la pena. Si el temporizador ya existe, invalide y vuelva a crear el temporizador. (Código no probado 🙂

 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { if (myTimer) { if ([myTimer isValid]) { [myTimer invalidate]; } [myTimer release], myTimer = nil; } myTimer = [[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(userPaused:) userInfo:nil repeats:NO] retain]; } 

Cuando el usuario deja de escribir durante 2 segundos, se llamará a -userPaused: y su temporizador se invalidará automáticamente (aunque no será nulo). Cuando el usuario comienza a escribir de nuevo, se configurará un nuevo temporizador.

Pude adaptar la respuesta de Sven Tan a mi código existente en Swift. En mi caso, estoy enviando la cadena a un método que carga los resultados de búsqueda asincrónicos. Además, no estoy usando UISearchBar, sino más bien un viejo y simple UITextField.

 var currentTempQuery = "" ... func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if let t = textField.text { let s: NSString = t let newString = s.stringByReplacingCharactersInRange(range, withString: string).trim() NSObject.cancelPreviousPerformRequestsWithTarget(self, selector:#selector(MyViewController.sendSearchRequest(_:)), object: currentTermQuery) // Don't replace currentTermQuery until after the cancelPreviousPerformRequestWithTarget call currentTermQuery = newString performSelector(#selector(MyViewController.sendSearchRequest(_:)), withObject: newString, afterDelay: 1) } return true } 

Aquí está el selector que se está llamando:

 func sendSearchRequest(text: String?) { // Call async search method here... } 

La forma en que funciona cancelPreviousPerformRequestsWithTarget es que debe pasar el mismo destino, selector y objeto que se pasó en la llamada a performSelector para que se cancele la solicitud anterior. En mi implementación, dado que paso solo una cadena, necesito preservar la cadena de solicitud actual entre las llamadas para poder hacer referencia a ella para cancelar las solicitudes.

El resultado funciona para tipear y eliminar caracteres en mi UITextField. Solo se envía una búsqueda por cambio de término principal de búsqueda.

Como dije, similar a lo que publicó Sven Tan pero con un uso ligeramente diferente. Espero que esto ayude a algunas personas.

Excelente código y trabajo perfecto para mí. Lo encontré aquí Reemplazando un NSTimer con performSelector: withObject: afterDelay . Gracias a la solución de Ben … todas las bondades para él, simplemente la copio aquí para que sea fácil de encontrar.

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { //because the view can be unloaded we must store all data so that its state can be restred in viewDidLoad self.searchQuery = [textField.text stringByReplacingCharactersInRange:range withString:string]; SEL fetchSearchResults = @selector(fetchSearchResults); //cancel the previous search request [[self class] cancelPreviousPerformRequestsWithTarget:self selector:fetchSearchResults object:nil]; //perform the search in a seconds time. If the user enters addition data then this search will be cancelled by the previous line [self performSelector:fetchSearchResults withObject:nil afterDelay:1]; return YES; } - (void)fetchSearchResults { NSLog(@"performing search %@", self.searchQuery); ... } 

Bloquee el ingreso de texto a su búsqueda y haga que un NSTimer llame a un selector. Muestra un indicador de algún tipo para que el usuario no piense que algo anda mal. Cuando el selector dispara devuelve el control al usuario para continuar escribiendo

 [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(targetMethod:) userInfo:nil repeats:NO];