¿Cómo detectar la key de eliminación en un UITextField en iOS 8?

He subclasificado UITextField e implementado el método deleteBackward del protocolo UIKeyInput para detectar el retroceso presionado. Esto funciona bien en iOS 7 pero no en iOS 8.

deleteBackward ya no se llama en UITextField cuando presiono la tecla de retroceso.

Revisé la documentation y las notas de la versión y nada apunta a la razón por la cual esto podría suceder. ¿Algún puntero?

Debe search un ejemplo para MBContactPicker en github. Eliminación de contactos en MBContactPicker mediante el button Retroceso en iOS8 probado por mí. ¡Y funciona mucho! Puedes usar su como ejemplo.

El autor de MBContactPicker usa el siguiente método: cuando UITextField debe estar vacío (o antes de la llamada becomeFirstResponder cuando está vacío), guarda allí un único símbolo de espacio en blanco. Y luego, cuando presiona el button Retroceso (cuando el foco se estableció al final del text de su UITextField), el método

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)text 

trabajará. En su interior debe usar un cheque como este:

 NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:text]; BOOL isPressedBackspaceAfterSingleSpaceSymbol = [text isEqualToString:@""] && [resultString isEqualToString:@""] && range.location == 0 && range.length == 1; if (isPressedBackspaceAfterSingleSpaceSymbol) { // your actions for deleteBackward actions } 

Por lo tanto, siempre debe controlar que UITextField contenga un solo espacio en blanco.

Esto no es hackear. Entonces, el usuario no notará que algo de comportamiento fue cambiado.

Mucha gente ha estado diciendo que esto es un error, pero dado que este problema aún existe en el GM, estoy empezando a pensar que podría ser un cambio en la lógica. Dicho esto, escribí este código para mi aplicación y lo probé en iOS 7-8.

Agregue el siguiente método a su subclass UITextField .

 - (BOOL)keyboardInputShouldDelete:(UITextField *)textField { BOOL shouldDelete = YES; if ([UITextField instancesRespondToSelector:_cmd]) { BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd]; if (keyboardInputShouldDelete) { shouldDelete = keyboardInputShouldDelete(self, _cmd, textField); } } BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8); BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f); if (![textField.text length] && isIos8 && isLessThanIos8_3) { [self deleteBackward]; } return shouldDelete; } 

Este código es ligeramente anterior a la línea roja de las API privadas, sin embargo, no debería tener problemas para usarlo. Mi aplicación con este código está en la tienda de aplicaciones.

Para explicar un poco, llamamos a la súper implementación de este método para evitar perder código. Después iban a llamar -deleteBackward si no hay text y la versión de iOS está entre 8-8.2.

EDITAR : 1/22/15

También podría ser útil subclasificar el método -deleteBackward de su subclass UITextField . Esto corrige algunos errores condicionales. Un ser si usa un keyboard personalizado. Este es un ejemplo del método.

 - (void)deleteBackward { BOOL shouldDismiss = [self.text length] == 0; [super deleteBackward]; if (shouldDismiss) { if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) { [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""]; } } } 

EDIT : 13/04/15

Como comentó @ Gee.E, iOS 8.3 ha solucionado este problema. El código se ha actualizado para reflejar los cambios.

Puede detectar cuándo el usuario elimina el text utilizando retroceso mediante la implementación del método delegado UITextField:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (range.length==1 && string.length==0) NSLog(@"backspace tapped"); return YES; } 

Swift 2.2:

 func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { if text == "" { print("Backspace has been pressed") } return true } 

En iOS8, algunos keyboards personalizados eliminan palabras enteras, así que solo verifique string.length está OK.

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (string.length==0) { //Delete any cases if(range.length > 1){ //Delete whole word } else if(range.length == 1){ //Delete single letter } else if(range.length == 0){ //Tap delete key when textField empty } } return YES; } 

Versión Swift 2.0 para detectar la supresión basada en BackSpace, haciendo reference a la publicación de códigos de los souls

 //For Detecting Backspace based Deletion of Entire Word in TextField func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if (range.length == 1 && string.isEmpty){ print("Used Backspace") } return true } 
 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { const char * _char = [string cStringUsingEncoding:NSUTF8StringEncoding]; int isBackSpace = strcmp(_char, "\b"); if (isBackSpace == -8) { NSLog(@"Backspace was pressed"); } return YES; } 

Básicamente, este método detecta qué button está presionando (o acaba de presionar). Esta input viene como un NSString. Convertimos este NSString a un tipo C char y luego lo comparamos con el carácter tradicional de retroceso (\ b). Entonces, si este strcmp es igual a -8, podemos detectarlo como un retroceso.

Rápido 2:

 if (string.characters.count == 0 && range.length == 1) { return true } 

deberías usar esta string.characters.count