cocoa - sierra - xcode ios 12
vinculando NSTextField a NSNumber (4)
Estoy tratando de usar un NSTextField para la entrada de usuario entero. El campo de texto está vinculado a una propiedad NSNumber y en el método setter limpie el valor de entrada (asegúrese de que sea un int) y establezca la propiedad si es necesario. Envío el willChangeValueForKey: y didChangeValueForKey :, pero la UI no se actualiza a los nuevos valores mientras ese campo de texto todavía está activo.
Entonces, por ejemplo, puedo escribir "12abc" en el campo de texto que el método setter limpia hasta "12", pero el campo de texto todavía muestra "12abc".
He marcado "Actualización continua de valor" en el constructor de interfaz.
(También he notado que el método setter recibe un NSString, no un NSNumber. ¿Es eso normal?)
¿Cuál es la forma correcta de conectar un NSTextField a un NSNumber? ¿Cómo se ve el método setter para la propiedad? ¿Cómo evitar que los valores no numéricos aparezcan en el campo de texto?
Como mencionó Ben, una forma de hacerlo es adjuntar un NSNumberFormatter a su campo de texto, lo cual es bastante trivial para configurar en el constructor de interfaz y probablemente Just Work ™.
Si no le gustan los diálogos modales que NSNumberFormatter lanza a sus usuarios cuando ingresan valores no numéricos, puede crear una subclase de NSNumberFormatter para implementar un comportamiento de formato diferente, ''más tolerante''. Creo que reemplazando - numberFromString: quitar los caracteres no numéricos antes de llamar a la implementación de super debería hacer el truco.
Otro enfoque es crear y registrar su propia subclase NSValueTransformer para analizar cadenas en NSNumbers y viceversa, pero yo trataría de usar un NSNumberFormatter primero ya que es claramente la clase que se ha diseñado para este propósito exacto.
Creo que debes configurar un formateador de números para tu NSTextField
.
Lea sobre formateadores en el sitio web de Apple: Aplicación de formateadores .
Envío el willChangeValueForKey: y didChangeValueForKey :, pero la UI no se actualiza a los nuevos valores mientras ese campo de texto todavía está activo.
Hay muy pocas razones para enviar esos mensajes. Por lo general, puedes hacer el mismo trabajo mejor y más limpiamente implementando y usando accesadores (o, mejor aún, propiedades). KVO enviará las notificaciones cuando lo haga.
En su caso, desea rechazar o filtrar entradas falsas (como "12abc"). La herramienta correcta para esta tarea es la Validación de valores clave.
Para habilitar esto, marque la casilla "Validar inmediatamente" en el enlace en IB e implemente un método de validación.
Filtración:
- (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError {
NSString *salvagedNumericPart;
//Determine whether you can salvage a numeric part from the string; in your example, that would be “12”, chopping off the “abc”.
*newValue = salvagedNumericPart; //@"12"
return (salvagedNumericPart != nil);
}
Rechazando:
- (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError {
BOOL isEntirelyNumeric;
//Determine whether the whole string (perhaps after stripping whitespace) is a number. If not, reject it outright.
if (isEntirelyNumeric) {
//The input was @"12", or it was @" 12 " or something and you stripped the whitespace from it, so *newValue is @"12".
return YES;
} else {
if (outError) {
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code: NSKeyValueValidationError userInfo:nil];
}
//Note: No need to set *newValue here.
return NO;
}
}
(También he notado que el método setter recibe un NSString, no un NSNumber. ¿Es eso normal?)
Sí, a menos que use un transformador de valor que transforme cadenas en números, conecte un formateador numérico a la salida del formatter
, o sustituya un NSNumber por NSString en su método de validación.
Hay un comentario importante sobre la excelente respuesta de Peter Hosey que me gustaría llevar al nivel superior (porque lo perdí en mi primer pase).
Si desea validar / modificar NSTextField cada vez que se ingresa un carácter, en lugar de solo cuando el usuario envía el campo, no puede obtener lo que desea de los enlaces solo. - (void)controlTextDidChange:(NSNotification *)aNotification
asignar un delegado al campo de texto y luego implementar - (void)controlTextDidChange:(NSNotification *)aNotification
en el delegado. Esto se llamará cada vez que el texto cambie. Si lo desea, puede llamar al validador de valor en controlTextDidChange
.
Por ejemplo:
- (void)controlTextDidChange:(NSNotification *)aNotification
{
NSError *outError;
NSControl *textField = [aNotification object];
NSString *myText = [textField stringValue];
// myObject is the model object that owns the text in question
// the validator can modify myText by reference
[myObject validateValue:&myText error:&outError]];
// update the NSNextField with the validated text
[postingObject setStringValue:myText];
}