mardi 20 janvier 2015

Using NSCoder and NSKeyedArchiver with runtime reflection to deep copy a custom class

I'd like to use



- (id)initWithCoder:(NSCoder *)coder


and



- (void)encodeWithCoder:(NSCoder *)coder


to encode a custom class for copying (using NSKeyedArchiver etc)


My custom class contains a large number of iVars. Instead of listing all of these in the encoding code I'd like to use reflection to simply enumerate over all the properties in the custom class and encode/decode each property from within a loop.


I'll end up with code that looks a bit like this:



- (id)initWithCoder:(NSCoder *)coder
{
if ((self = [super init]))
{
[self codeWithCoder:coder andDirection:0];
}
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[self codeWithCoder:coder andDirection:1];
}

-(void)codeWithCoder:(NSCoder *)coder andDirection:(NSInteger)direction
{
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);



unsigned i;
for (i = 0; i < count; i++)
{
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
const char * type = property_getAttributes(property);
NSString * typeString = [NSString stringWithUTF8String:type];
NSArray * attributes = [typeString componentsSeparatedByString:@","];
NSString * typeAttribute = [attributes objectAtIndex:0];
NSString * propertyType = [typeAttribute substringFromIndex:1];
const char * rawPropertyType = [propertyType UTF8String];

if (strcmp(rawPropertyType, @encode(float)) == 0) {
//it's a float
if (direction==0) ??? = [coder decodeFloatForKey:name];
else [coder encodeFloat:???? forKey:name];

} else if (strcmp(rawPropertyType, @encode(bool)) == 0) {
//it's a bool
if (direction==0) ??? = [coder decodeBoolForKey:name];
else [coder encodeBool:???? forKey:name];

} else if (strcmp(rawPropertyType, @encode(int)) == 0) {
//it's an int
if (direction==0) ??? = [coder decodeIntegerForKey:name];
else [coder encodeInteger:???? forKey:name];

} else if (strcmp(rawPropertyType, @encode(id)) == 0) {
//it's some sort of object
if (direction==0) ??? = [coder decodeObjectForKey:name];
else [coder encodeObject:???? forKey:name];

}
}

free(properties);





}


My question is this: what do I replace the ??? and ???? fragments with to get and set the actual ivar values?






Aucun commentaire:

Enregistrer un commentaire