lao lao - 6 months ago 24
iOS Question

NSCode: encoder and decoder for primitive types

I was trying to create a generic encoder and decoder for my model classes. I was trying to find a way to call the "encode method" for all types of properties, either objects (NSString, NSNumber, NSArray, etc...) and primitive types. And I saw someone doing the following. And I was wondering if this would a correct way to do it.

Properties:

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


Enconder and Decoder Code:

- (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;
}


I was not sure if this is a correct way, or if other program or object could write in the same memory space of the primitive properties. If the method above is correct, what is the difference between the above and this:

The way I thought was correct:

- (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;
}


I tested and both methods returned the correct values.

Answer

Both methods will work.

The first is particularly clever, being that valueForKey: will always return an NSObject, even when the value is actually a primitive, so float/int/bool types will be wrapped in an NSNumber automatically by the KVC getter, and unwrapped in the KVC setter.

It might be possible to use this to implement some sort of generic encode/decode functions that operate on an array of property keys.

However, the second example is the standard way to do it, and the way I'd probably recommend. Sometimes you've got to write boilerplate code!

Comments