From 84ad413e07b579c5afc1277947a8a7d53421eb9a Mon Sep 17 00:00:00 2001 From: Ivan Zezyulya Date: Thu, 1 Nov 2012 19:45:16 +0700 Subject: [PATCH 1/6] Use methods for both retrieving/storing properties; Use ARC --- NSObject+NSCoding.h | 12 +++++ NSObject+NSCoding.m | 127 +++++++++++++++++++++++++++----------------- 2 files changed, 90 insertions(+), 49 deletions(-) mode change 100644 => 100755 NSObject+NSCoding.h mode change 100644 => 100755 NSObject+NSCoding.m diff --git a/NSObject+NSCoding.h b/NSObject+NSCoding.h old mode 100644 new mode 100755 index 64c1fde..5acf3b3 --- a/NSObject+NSCoding.h +++ b/NSObject+NSCoding.h @@ -16,3 +16,15 @@ - (NSDictionary *)properties; @end + +#define AUTO_ENCODE - (void)encodeWithCoder:(NSCoder *)coder { \ + [self autoEncodeWithCoder:coder]; \ +} + + +#define AUTO_DECODE - (id)initWithCoder:(NSCoder *)coder { \ + if ((self = [super init])) { \ + [self autoDecode:coder]; \ + } \ + return self; \ +} diff --git a/NSObject+NSCoding.m b/NSObject+NSCoding.m old mode 100644 new mode 100755 index b7bf528..88cf731 --- a/NSObject+NSCoding.m +++ b/NSObject+NSCoding.m @@ -9,24 +9,25 @@ #import "NSObject+NSCoding.h" #import - @implementation NSObject (NSCoding) -- (NSMutableDictionary *)propertiesForClass:(Class)klass { +- (NSMutableDictionary *) propertiesForClass:(Class)klass +{ - NSMutableDictionary *results = [[[NSMutableDictionary alloc] init] autorelease]; + NSMutableDictionary *results = [NSMutableDictionary new]; unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList(klass, &outCount); for(i = 0; i < outCount; i++) { objc_property_t property = properties[i]; - + NSString *pname = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding]; NSString *pattrs = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding]; - pattrs = [[pattrs componentsSeparatedByString:@","] objectAtIndex:0]; + NSArray *comps = [pattrs componentsSeparatedByString:@","]; + pattrs = [comps objectAtIndex:0]; pattrs = [pattrs substringFromIndex:1]; - + [results setObject:pattrs forKey:pname]; } free(properties); @@ -38,16 +39,21 @@ - (NSMutableDictionary *)propertiesForClass:(Class)klass { return results; } -- (NSDictionary *)properties { +- (NSDictionary *) properties +{ return [self propertiesForClass:[self class]]; } -- (void)autoEncodeWithCoder:(NSCoder *)coder { +- (void) autoEncodeWithCoder:(NSCoder *)coder +{ NSDictionary *properties = [self properties]; - for (NSString *key in properties) { + + for (NSString *key in properties) + { NSString *type = [properties objectForKey:key]; id value; unsigned long long ullValue; + long long llValue; BOOL boolValue; float floatValue; double doubleValue; @@ -69,7 +75,7 @@ - (void)autoEncodeWithCoder:(NSCoder *)coder { className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1]; Class class = NSClassFromString(className); value = [self performSelector:NSSelectorFromString(key)]; - + // only decode if the property conforms to NSCoding if([class conformsToProtocol:@protocol(NSCoding)]){ [coder encodeObject:value forKey:key]; @@ -106,6 +112,11 @@ - (void)autoEncodeWithCoder:(NSCoder *)coder { [invocation getReturnValue:&ullValue]; [coder encodeObject:[NSNumber numberWithUnsignedLongLong:ullValue] forKey:key]; break; + case 'q': // long long + [invocation invoke]; + [invocation getReturnValue:&llValue]; + [coder encodeObject:[NSNumber numberWithLongLong:llValue] forKey:key]; + break; case 'l': // long [invocation invoke]; [invocation getReturnValue:&longValue]; @@ -127,95 +138,113 @@ - (void)autoEncodeWithCoder:(NSCoder *)coder { } } -- (void)autoDecode:(NSCoder *)coder { +- (void) autoDecode:(NSCoder *)coder +{ NSDictionary *properties = [self properties]; - for (NSString *key in properties) { + + for (NSString *key in properties) + { + NSString *capitalizedKey = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] capitalizedString]]; + NSString *selectorString = [NSString stringWithFormat:@"set%@:", capitalizedKey]; + SEL selector = NSSelectorFromString(selectorString); + NSMethodSignature *signature = [self methodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setSelector:selector]; + [invocation setTarget:self]; + NSString *type = [properties objectForKey:key]; id value; NSNumber *number; - unsigned int addr; NSInteger i; CGFloat f; BOOL b; double d; unsigned long ul; unsigned long long ull; + long long ll; long longValue; unsigned unsignedValue; short shortValue; - Ivar ivar; - double *varIndex; - - NSString *className; - - switch ([type characterAtIndex:0]) { - case '@': // object - if ([[type componentsSeparatedByString:@"\""] count] > 1) { - className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1]; + + switch ([type characterAtIndex:0]) + { + case '@': // object + if ([[type componentsSeparatedByString:@"\""] count] > 1) + { + NSString *className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1]; Class class = NSClassFromString(className); // only decode if the property conforms to NSCoding - if ([class conformsToProtocol:@protocol(NSCoding )]){ - value = [[coder decodeObjectForKey:key] retain]; - addr = (NSInteger)&value; - object_setInstanceVariable(self, [key UTF8String], *(id**)addr); + if ([class conformsToProtocol:@protocol(NSCoding)]){ + @try { + value = [coder decodeObjectForKey:key]; + } + @catch (NSException *exception) { + NSLog(@"Warning: %@", exception); + continue; + } + [self performSelector:selector withObject:value]; } } break; case 'c': // bool - number = [coder decodeObjectForKey:key]; + number = [coder decodeObjectForKey:key]; b = [number boolValue]; - addr = (NSInteger)&b; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&b atIndex:2]; + [invocation invoke]; break; case 'f': // float - number = [coder decodeObjectForKey:key]; + number = [coder decodeObjectForKey:key]; f = [number floatValue]; - addr = (NSInteger)&f; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&f atIndex:2]; + [invocation invoke]; break; - case 'd': // double + case 'd': // double number = [coder decodeObjectForKey:key]; d = [number doubleValue]; - if ((ivar = class_getInstanceVariable([self class], [key UTF8String]))) { - varIndex = (double *)(void **)((char *)self + ivar_getOffset(ivar)); - *varIndex = d; - } + [invocation setArgument:&d atIndex:2]; + [invocation invoke]; break; case 'i': // int number = [coder decodeObjectForKey:key]; i = [number intValue]; - addr = (NSInteger)&i; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&i atIndex:2]; + [invocation invoke]; break; case 'L': // unsigned long number = [coder decodeObjectForKey:key]; ul = [number unsignedLongValue]; - addr = (NSInteger)&ul; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&ul atIndex:2]; + [invocation invoke]; + break; + case 'q': // long long + number = [coder decodeObjectForKey:key]; + ll = [number longLongValue]; + [invocation setArgument:&ll atIndex:2]; + [invocation invoke]; break; case 'Q': // unsigned long long number = [coder decodeObjectForKey:key]; ull = [number unsignedLongLongValue]; - addr = (NSInteger)&ull; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&ull atIndex:2]; + [invocation invoke]; break; case 'l': // long number = [coder decodeObjectForKey:key]; longValue = [number longValue]; - addr = (NSInteger)&longValue; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&longValue atIndex:2]; + [invocation invoke]; break; case 'I': // unsigned number = [coder decodeObjectForKey:key]; unsignedValue = [number unsignedIntValue]; - addr = (NSInteger)&unsignedValue; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&unsignedValue atIndex:2]; + [invocation invoke]; break; case 's': // short number = [coder decodeObjectForKey:key]; shortValue = [number shortValue]; - addr = (NSInteger)&shortValue; - object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr); + [invocation setArgument:&shortValue atIndex:2]; + [invocation invoke]; break; default: From 9095b660190a51eee879c2993df1e47961090adf Mon Sep 17 00:00:00 2001 From: Ivan Zezyulya Date: Fri, 2 Nov 2012 18:32:24 +0700 Subject: [PATCH 2/6] Use ARC in Archiver.m --- Archiver.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Archiver.m b/Archiver.m index ff38994..d51fb51 100644 --- a/Archiver.m +++ b/Archiver.m @@ -14,7 +14,7 @@ + (id)retrieve:(NSString *)key { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *filePath = [documentsDirectory stringByAppendingString:[NSString stringWithFormat:@"/%@.archive", key]]; - return [[[NSKeyedUnarchiver unarchiveObjectWithFile:filePath] retain] autorelease]; + return [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; } + (BOOL)persist:(id)object key:(NSString *)key { From 723e3c9400fdbace11fc884c6e5215622c574f4d Mon Sep 17 00:00:00 2001 From: Kostas Antonopoulos Date: Fri, 31 Jan 2014 18:01:01 +0200 Subject: [PATCH 3/6] Silenced warning about leak in performSelector --- NSObject+NSCoding.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NSObject+NSCoding.m b/NSObject+NSCoding.m index 88cf731..d7ce16e 100755 --- a/NSObject+NSCoding.m +++ b/NSObject+NSCoding.m @@ -182,7 +182,10 @@ - (void) autoDecode:(NSCoder *)coder NSLog(@"Warning: %@", exception); continue; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" [self performSelector:selector withObject:value]; +#pragma clang diagnostic pop } } break; From 7be9a8102ba030c976abd7e91079b001f33d494b Mon Sep 17 00:00:00 2001 From: Kostas Antonopoulos Date: Mon, 17 Mar 2014 01:24:32 +0200 Subject: [PATCH 4/6] Added pragma to suppress warning --- NSObject+NSCoding.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NSObject+NSCoding.m b/NSObject+NSCoding.m index d7ce16e..7215986 100755 --- a/NSObject+NSCoding.m +++ b/NSObject+NSCoding.m @@ -74,8 +74,10 @@ - (void) autoEncodeWithCoder:(NSCoder *)coder if ([[type componentsSeparatedByString:@"\""] count] > 1) { className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1]; Class class = NSClassFromString(className); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" value = [self performSelector:NSSelectorFromString(key)]; - +#pragma clang diagnostic pop // only decode if the property conforms to NSCoding if([class conformsToProtocol:@protocol(NSCoding)]){ [coder encodeObject:value forKey:key]; From 3dea58c6b7c4fbc9b9d3ac6733fea86eeb73daff Mon Sep 17 00:00:00 2001 From: Kostas Antonopoulos Date: Mon, 28 Apr 2014 10:31:03 +0300 Subject: [PATCH 5/6] Added check for type B which is boolean in 64bit devices --- NSObject+NSCoding.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NSObject+NSCoding.m b/NSObject+NSCoding.m index 7215986..af0a984 100755 --- a/NSObject+NSCoding.m +++ b/NSObject+NSCoding.m @@ -68,7 +68,6 @@ - (void) autoEncodeWithCoder:(NSCoder *)coder NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setSelector:NSSelectorFromString(key)]; [invocation setTarget:self]; - switch ([type characterAtIndex:0]) { case '@': // object if ([[type componentsSeparatedByString:@"\""] count] > 1) { @@ -84,6 +83,7 @@ - (void) autoEncodeWithCoder:(NSCoder *)coder } } break; + case 'B': // bool for 64bit case 'c': // bool [invocation invoke]; [invocation getReturnValue:&boolValue]; @@ -191,6 +191,7 @@ - (void) autoDecode:(NSCoder *)coder } } break; + case 'B': // bool for 64bit case 'c': // bool number = [coder decodeObjectForKey:key]; b = [number boolValue]; From 3cddb7039aab015425f426bbd5e531083c3cfe59 Mon Sep 17 00:00:00 2001 From: Kostas Antonopoulos Date: Mon, 24 Nov 2014 02:12:31 +0200 Subject: [PATCH 6/6] Added import for CoreGraphics in NSOject+NSCoding.m to support CGFloat type --- NSObject+NSCoding.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NSObject+NSCoding.m b/NSObject+NSCoding.m index 6649e88..ee74a56 100644 --- a/NSObject+NSCoding.m +++ b/NSObject+NSCoding.m @@ -8,7 +8,7 @@ #import "NSObject+NSCoding.h" #import - +#import @implementation NSObject (NSCoding)