2012-02-28 9 views
6

Estaba intentando crear un codificador y decodificador genérico para mis clases de modelo. Estaba intentando encontrar una forma de llamar al "método de codificación" para todos los tipos de propiedades, ya sean objetos (NSString, NSNumber, NSArray, etc.) y tipos primitivos. Y vi a alguien haciendo lo siguiente. Y me preguntaba si esta sería una forma correcta de hacerlo.NSCode: codificador y decodificador para los tipos primitivos

Propiedades:

@property (assign,nonatomic) int integerP; 
@property (assign,nonatomic) float floatP; 
@property (assign,nonatomic) BOOL boolP; 

Enconder y decodificador Código:

- (void)encodeWithCoder:(NSCoder *)encoder 
{ 
    id object2 = [self valueForKey:@"integerP"]; 
    id object3 = [self valueForKey:@"floatP"]; 
    id object4 = [self valueForKey:@"boolP"]; 


    [encoder encodeObject:object2 forKey:@"integerP"]; 
    [encoder encodeObject:object3 forKey:@"floatP"]; 
    [encoder encodeObject:object4 forKey:@"boolP"]; 

    //[self setValue:[NSNumber numberWithInt:90] forKey:@"heightR"]; 

    //NSLog(@"%@",[self valueForKey:@"heightR"]); 


} 

- (id)initWithCoder:(NSCoder *)decoder 
{ 
    self = [super init]; 
    if(self != nil) 
    { 

     id object2 = [decoder decodeObjectForKey:@"integerP"]; 
     [self setValue:object2 forKey:@"integerP"]; 
     id object3 = [decoder decodeObjectForKey:@"floatP"]; 
     [self setValue:object3 forKey:@"floatP"]; 
     id object4 = [decoder decodeObjectForKey:@"boolP"]; 
     [self setValue:object4 forKey:@"boolP"]; 

    } 
    return self; 
} 

no estaba seguro de si se trata de una forma correcta, o si otro programa u objeto podría escribir en el mismo espacio de memoria de las propiedades primitivas. Si el método anterior es correcta, lo que es la diferencia entre el anterior y este:

La manera que pensé que era correcta:

- (void)encodeWithCoder:(NSCoder *)encoder 
{ 


    [encoder encodeInt:integerP forKey:@"integerP"]; 
    [encoder encodeFloat:floatP forKey:@"floatP"]; 
    [encoder encodeBool:boolP forKey:@"boolP"]; 

    //[self setValue:[NSNumber numberWithInt:90] forKey:@"heightR"]; 

    //NSLog(@"%@",[self valueForKey:@"heightR"]); 


} 

- (id)initWithCoder:(NSCoder *)decoder 
{ 
    self = [super init]; 
    if(self != nil) 
    { 
     integerP = [decoder decodeIntForKey:@"integerP"]; 
     floatP = [decoder decodeFloatForKey:@"floatP"]; 
     boolP = [decoder decodeBoolForKey:@"boolP"]; 


    } 
    return self; 
} 

Probé y ambos métodos de regresar los valores correctos.

+0

que no entiendo. Ya hay métodos para codificar/decodificar tipos primitivos, ¿por qué no los usaría? Para mí, el segundo método es más correcto. – Bejil

Respuesta

8

Ambos métodos funcionarán.

La primera es particularmente inteligente, siendo que valueForKey: siempre devolverá un NSObject, incluso cuando el valor es en realidad una primitiva, por lo que flotan tipos/int/bool serán envueltos en una NSNumber automáticamente por el getter KVC, y sin envolver en el setter de KVC.

Podría ser posible utilizar esto para implementar algún tipo de funciones genéricas de codificación/descodificación que operan en una matriz de claves de propiedad.

Sin embargo, el segundo ejemplo es la manera estándar de hacerlo, y la forma en que probablemente lo recomendaría. ¡A veces tienes que escribir un código repetitivo!

+0

Es bueno saber que ambos funcionarían y que está bien usarlos. Pero, ¿por qué recomendarías el segundo? ¿Conoces algún tipo de ganancia de rendimiento si usas el segundo método? - Por ahora, tengo 2 opciones para escribir mi enconde/decode genérico, ya sea usar el primer método de codificación publicado anteriormente o usar un NSDictionary que contendría todas mis propiedades primitivas. ¿De qué manera recomendarías? – lao

+0

No lo sé con certeza, pero creo que habría una diferencia de rendimiento insignificante. Si estuviera almacenando las primitivas en un NSDictionary, tendría que convertirlas a NSNumbers antes de hacerlo de todos modos, por lo que efectivamente es lo mismo. Mi recomendación sería simplemente escribir la codificación/decodificación manualmente, pero si quiere probar una codificación/descodificación genérica, la primera sería la mejor opción. Sin embargo, si el rendimiento es un gran problema, realmente debería considerar pasar a un modelo de datos básicos. NSCoder es bastante lento en la codificación de árboles de objetos grandes. – joerick

+0

Sí, imagino que también podría ser una pequeña diferencia de rendimiento. Por ahora, creo que escribiré el codificador/decodificador genérico usando el primer método. No creo que me cause una gran diferencia de rendimiento y me ahorrará mucho tiempo para otros proyectos. Y sí, usaré el modelo de datos básicos para objetos grandes, solo planeo usar NSCoder para objetos pequeños. ¡Pero gracias! – lao

1

¡Su primer método parece muy extraño!

En Objective-C float/int/BOOL no son "Objeto". Puede convertirlos en un NSNumber llamando:

Pero su segunda solución se ve bien.
Sólo use decodeObjectForKey de objetos como NSArray, etc. o su propia clase (en la que también hay que añadir los métodos de codificación/decodificación!)

Y dejar los dedos de setValue y valueForKey.

1

Prueba esto:

BaseModel.h

@interface BaseModel : NSObject<NSCoding> 
@end 

BaseModel.m

- (NSArray *)keysForEncoding 
{ 
    [NSException raise:@"keysForEncoding" format:@"keysForEncoding must be implemented in child class!"]; 
    //example implementation in child class: 
    //return @[@"airtime", @"channelID", @"duration", @"programID", @"shortTitle"]; 
    return nil; 
} 


-(void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    for(NSString* key in [self keysForEncoding]) 
    { 
     [aCoder encodeObject:[self valueForKey:key] forKey:key]; 
    } 
} 

-(id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super init]; 
    if (self) { 
     for (NSString* key in [self keysForEncoding]) { 
      [self setValue:[aDecoder decodeObjectForKey:key] forKey:key]; 
     } 
    } 
    return self; 
} 

Entonces derivar de esa clase base de su clase con datos reales.

Ejemplo de clase simple:

EPGData.h

@interface EPGData : BaseModel 
    @property(nonatomic, assign) NSTimeInterval airtime; //date in 1970 format 
    @property(nonatomic, assign) int channelID; 
    @property(nonatomic, assign) float duration; //in seconds 
    @property(nonatomic, assign) unsigned int programID; 
    @property(nonatomic, strong) NSString* shortTitle; 
    @end 

EPGData.m

- (NSArray *)keysForEncoding; 
{ 
    return [NSArray arrayWithObjects:@"airtime", @"channelID", @"duration", @"programID", @"shortTitle", nil]; 
} 
Cuestiones relacionadas