Created
February 6, 2014 01:17
-
-
Save pixelrevision/8836729 to your computer and use it in GitHub Desktop.
Property Serializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
typedef enum { | |
PXRPropSerializerTypeUnknown, | |
PXRPropSerializerTypeFloat, | |
PXRPropSerializerTypeDouble, | |
PXRPropSerializerTypeInt, | |
PXRPropSerializerTypeClass, | |
PXRPropSerializerTypeBool | |
}PXRPropSerializerType; | |
@interface PXRPropSerializer : NSObject <NSCoding> | |
- (NSArray *)ignoredProperties; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "PXRPropSerializer.h" | |
@implementation PXRPropSerializer | |
- (id)initWithCoder:(NSCoder *)aDecoder{ | |
self = [super init]; | |
NSArray *classesToDecode = [self classesToSerialize]; | |
for(Class classToDecode in classesToDecode){ | |
NSKeyedUnarchiver *unarchiver = (NSKeyedUnarchiver *)aDecoder; | |
unsigned int numOfProperties; | |
objc_property_t *properties = class_copyPropertyList(classToDecode, &numOfProperties); | |
BOOL ignore; | |
for(int i=0; i<numOfProperties; i++) { | |
objc_property_t property = properties[i]; | |
ignore = [self ignoreProperty:property]; | |
if(!ignore){ | |
[self decodeProperty:property withUnarchiver:unarchiver]; | |
} | |
} | |
free(properties); | |
} | |
return self; | |
} | |
- (void)decodeProperty:(objc_property_t)property withUnarchiver:(NSKeyedUnarchiver *)unarchiver{ | |
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding]; | |
PXRPropSerializerType type = [self typeForProperty:property]; | |
switch (type) { | |
case PXRPropSerializerTypeUnknown: | |
NSLog(@"unknown property %@ not decoding", propertyName); | |
break; | |
case PXRPropSerializerTypeBool: | |
[self setValue:[NSNumber numberWithBool:[unarchiver decodeBoolForKey:propertyName]] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeFloat: | |
[self setValue:[NSNumber numberWithFloat:[unarchiver decodeFloatForKey:propertyName]] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeInt: | |
[self setValue:[NSNumber numberWithInt:[unarchiver decodeIntForKey:propertyName]] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeDouble: | |
[self setValue:[NSNumber numberWithDouble:[unarchiver decodeDoubleForKey:propertyName]] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeClass: | |
[self setValue:[unarchiver decodeObjectForKey:propertyName] forKey:propertyName]; | |
break; | |
} | |
} | |
- (void)encodeWithCoder:(NSCoder *)aCoder{ | |
NSArray *classesToEncode = [self classesToSerialize]; | |
for(Class classToEncode in classesToEncode){ | |
NSKeyedArchiver *archiver = (NSKeyedArchiver *)aCoder; | |
unsigned int numOfProperties; | |
objc_property_t *properties = class_copyPropertyList(classToEncode, &numOfProperties); | |
BOOL ignore; | |
for(int i=0; i<numOfProperties; i++) { | |
objc_property_t property = properties[i]; | |
ignore = [self ignoreProperty:property]; | |
if(!ignore){ | |
[self encodeProperty:property withArchiver:archiver]; | |
} | |
} | |
free(properties); | |
} | |
} | |
- (NSArray *)attributesOfProp:(objc_property_t)prop{ | |
const char * propAttr = property_getAttributes(prop); | |
NSString *propString = [NSString stringWithUTF8String:propAttr]; | |
NSArray *attrArray = [propString componentsSeparatedByString:@","]; | |
return attrArray; | |
} | |
- (void)encodeProperty:(objc_property_t)property withArchiver:(NSKeyedArchiver *)archiver{ | |
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding]; | |
PXRPropSerializerType type = [self typeForProperty:property]; | |
switch (type) { | |
case PXRPropSerializerTypeUnknown: | |
NSLog(@"unknown property %@ not encoding", propertyName); | |
break; | |
case PXRPropSerializerTypeBool: | |
[archiver encodeBool:[[self valueForKey:propertyName] boolValue] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeFloat: | |
[archiver encodeFloat:[[self valueForKey:propertyName] floatValue] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeDouble: | |
[archiver encodeDouble:[[self valueForKey:propertyName] doubleValue] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeInt: | |
[archiver encodeInt:[[self valueForKey:propertyName] integerValue] forKey:propertyName]; | |
break; | |
case PXRPropSerializerTypeClass: | |
[self encodeObjectForProperty:property withArchiver:archiver]; | |
break; | |
} | |
} | |
- (void)encodeObjectForProperty:(objc_property_t)property withArchiver:(NSKeyedArchiver *)archiver{ | |
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding]; | |
id object = [self valueForKey:propertyName]; | |
if(![[object class] conformsToProtocol:@protocol(NSCoding)]){ | |
NSLog(@"Not saving %@. does not conform to NSCoding", propertyName); | |
} | |
[archiver encodeObject:object forKey:propertyName]; | |
} | |
- (PXRPropSerializerType)typeForProperty:(objc_property_t)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){ | |
return PXRPropSerializerTypeFloat; | |
}else if (strcmp(rawPropertyType, @encode(int)) == 0){ | |
return PXRPropSerializerTypeInt; | |
}else if (strcmp(rawPropertyType, @encode(double)) == 0){ | |
return PXRPropSerializerTypeDouble; | |
}else if (strcmp(rawPropertyType, @encode(BOOL)) == 0){ | |
return PXRPropSerializerTypeBool; | |
}else if (strcmp(rawPropertyType, @encode(id)) == 0){ | |
return PXRPropSerializerTypeClass; | |
} | |
if([typeAttribute hasPrefix:@"T@"] && [typeAttribute length] > 1){ | |
NSString *typeClassName = [typeAttribute substringWithRange:NSMakeRange(3, [typeAttribute length]-4)]; | |
Class typeClass = NSClassFromString(typeClassName); | |
if(typeClass != nil){ | |
return PXRPropSerializerTypeClass; | |
} | |
} | |
return PXRPropSerializerTypeUnknown; | |
} | |
- (NSArray *)classesToSerialize{ | |
NSMutableArray *classes = [[NSMutableArray alloc] init]; | |
BOOL finished = NO; | |
Class superClass = [self class]; | |
while(!finished){ | |
if(superClass == [PXRPropSerializer class] || superClass == [NSObject class]){ | |
finished = YES; | |
}else{ | |
[classes addObject:superClass]; | |
superClass = [superClass superclass]; | |
} | |
} | |
return classes; | |
} | |
- (NSArray *)ignoredProperties{ | |
return @[]; | |
} | |
- (BOOL)ignoreProperty:(objc_property_t)property{ | |
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding]; | |
NSArray *ignored = [self ignoredProperties]; | |
for(NSString *ignore in ignored){ | |
if([propertyName isEqualToString:ignore]){ | |
return YES; | |
} | |
} | |
return NO; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment