2009-06-12 3 views
8

Lo que dice en la lata: me gustaría utilizar la sintaxis @property/@synthesize para definir una propiedad en mi clase Objective-C 2.0, pero quiero establecer restricciones en el rango de valores permitidos en la propiedad. Por ejemplo:¿Puedo validar un valor @property en Objective-C usando métodos @synthesized?

@interface MyClass : NSObject { 
    int myValue; 
} 

@property (nonatomic) int myValue; 

Implementación:

@implementation MyClass 

@synthesize myValue(test='value >= 0'); 

Tenga en cuenta que la sintaxis aquí es sólo un ejemplo. ¿Esto o algo así es posible? Alternativamente, ¿cuál es el equivalente literal de un setter sintetizado, de modo que puedo asegurarme de que utilizo las mismas reglas de retención de objetos en mis setters manuales que las que se usan en un sintetizador?

+0

Probablemente valga la pena etiquetar esto con 'cocoa' y 'macosx'. No tengo una reputación lo suficientemente alta para eso. – toholio

Respuesta

7

Suponiendo sus propiedades son de valor-clave compatible (como lo serían si está utilizando @synthesize) también se debe aplicar validadores compatibles clave-valor. Eche un vistazo a la documentación de Apple sobre el asunto: http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/Validation.html

Lo importante a tener en cuenta es que la validación no ocurre automáticamente, excepto cuando se utilizan ciertos tipos de enlace. Llame al validador directamente o llamando al validateValue:forKey:error:.

Puede invalidar el setter producido para llamar al validador antes de guardarlo, pero si está utilizando enlaces esto probablemente no sea lo que quiere hacer, ya que el validador se llamará más de una vez para una única modificación.

También tenga en cuenta que el validador puede cambiar el valor que se está validando.

Así que veamos su ejemplo (no probado, por cierto.No estoy cerca de un Mac):

@implementation MyClass 

@synthesize myValue; 

-(BOOL)validateMyValue:(id *)ioValue error:(NSError **)outError 
{ 
    if (*ioValue == nil) { 
    // trap this in setNilValueForKey 
    // alternative might be to create new NSNumber with value 0 here 
    return YES; 
    } 

    if ([*ioValue intValue] < 0) { 
    NSString *errorString = @"myValue must be greater than zero"; 
    NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorString 
                  forKey:NSLocalizedDescriptionKey]; 

    NSError *error = [[[NSError alloc] initWithDomain:@"MyValueError" 
               code:0 
              userInfo:userInfoDict] autorelease]; 

    *outError = error; 

    return NO; 
    } else { 
    return YES; 
    } 
} 

Si quisiera anular el colocador sintetizado y hacer que haga la validación (aún no probado):

- (void)setMyValue:(int)value { 

    id newValue = [NSNumber numberWithInt:value]; 
    NSError *errorInfo = nil; 

    if ([self validateMyValue:&newValue error:&errorInfo]) { 
    myValue = [newValue intValue]; 
    } 
} 

Se puede ver que teníamos para envolver el entero en una instancia NSNumber para hacer esto.

+4

De acuerdo con los documentos, no debe llamar al método de validación desde un setter: http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/Validation.html#//apple_ref/doc/uid/20002173-166962 –

2

Cuando usa @synthesize se generan los métodos de acceso. Puede implementar el suyo que sobrescribirá el generado.

Puede poner su propia implementación dentro de los métodos de acceso, p. Ej. puede agregar una verificación de valor antes de la asignación y así sucesivamente.

Puede omitir uno u otro o ambos, los que no implementa se generarán debido a @synthesize; si usa @dynamic, está especificando que proporcionará los descriptores durante la compilación o el tiempo de ejecución.

Los accesadores tendrán nombres derivados del nombre de la propiedad myproperty y setMyproperty. Las firmas de método son estándar, por lo que es fácil implementar el suyo propio. La implementación real depende de la definición de propiedad (copiar, retener, asignar) y si es de solo lectura o no (el programa de solo lectura no establece el acceso). Para más detalles, ver referencia objetivo-c.

Apple reference:

@synthesize Se utiliza el @synthesize palabra clave para indicar al compilador que debe sintetizar la incubadora y/o métodos getter de la propiedad si no se proporciona dentro de la @ Bloque de implementación.

@interface MyClass : NSObject 
{ 
    NSString *value; 
} 
@property(copy, readwrite) NSString *value; 
@end 


@implementation MyClass 
@synthesize value; 

- (NSString *)value { 
    return value; 
} 

- (void)setValue:(NSString *)newValue { 
    if (newValue != value) { 
     value = [newValue copy]; 
    } 
} 
@end 
Cuestiones relacionadas