5 // Created by Michael Mayo on 3/4/11.
6 // The OpenStack project is provided under the Apache 2.0 license.
9 #import "NSObject+NSCoding.h"
10 #import <objc/runtime.h>
11 //#import <objc/objc-class.h>
14 @implementation NSObject (NSCoding)
16 - (NSMutableDictionary *)propertiesForClass:(Class)klass {
18 NSMutableDictionary *results = [[[NSMutableDictionary alloc] init] autorelease];
20 unsigned int outCount, i;
21 objc_property_t *properties = class_copyPropertyList(klass, &outCount);
22 for(i = 0; i < outCount; i++) {
23 objc_property_t property = properties[i];
25 NSString *pname = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
26 NSString *pattrs = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
28 pattrs = [[pattrs componentsSeparatedByString:@","] objectAtIndex:0];
29 pattrs = [pattrs substringFromIndex:1];
31 [results setObject:pattrs forKey:pname];
35 if ([klass superclass] != [NSObject class]) {
36 [results addEntriesFromDictionary:[self propertiesForClass:[klass superclass]]];
42 - (NSDictionary *)properties {
43 return [self propertiesForClass:[self class]];
46 - (void)autoEncodeWithCoder:(NSCoder *)coder {
47 NSDictionary *properties = [self properties];
48 for (NSString *key in properties) {
49 NSString *type = [properties objectForKey:key];
51 unsigned long long ullValue;
56 unsigned long ulValue;
59 NSMethodSignature *signature = [self methodSignatureForSelector:NSSelectorFromString(key)];
60 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
61 [invocation setSelector:NSSelectorFromString(key)];
62 [invocation setTarget:self];
64 switch ([type characterAtIndex:0]) {
66 if ([[type componentsSeparatedByString:@"\""] count] > 1) {
67 className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1];
68 value = [self performSelector:NSSelectorFromString(key)];
70 // only decode if the property conforms to NSCoding
71 if (class_conformsToProtocol(NSClassFromString(className), @protocol(NSCoding))) {
72 [coder encodeObject:value forKey:key];
78 [invocation getReturnValue:&boolValue];
79 [coder encodeObject:[NSNumber numberWithBool:boolValue] forKey:key];
83 [invocation getReturnValue:&floatValue];
84 [coder encodeObject:[NSNumber numberWithFloat:floatValue] forKey:key];
88 [invocation getReturnValue:&doubleValue];
89 [coder encodeObject:[NSNumber numberWithDouble:doubleValue] forKey:key];
93 [invocation getReturnValue:&intValue];
94 [coder encodeObject:[NSNumber numberWithInt:intValue] forKey:key];
96 case 'L': // unsigned long
98 [invocation getReturnValue:&ulValue];
99 [coder encodeObject:[NSNumber numberWithUnsignedLong:ulValue] forKey:key];
101 case 'Q': // unsigned long long
103 [invocation getReturnValue:&ullValue];
104 [coder encodeObject:[NSNumber numberWithUnsignedLongLong:ullValue] forKey:key];
112 - (void)autoDecode:(NSCoder *)coder {
113 NSDictionary *properties = [self properties];
114 for (NSString *key in properties) {
115 NSString *type = [properties objectForKey:key];
124 unsigned long long ull;
129 switch ([type characterAtIndex:0]) {
131 if ([[type componentsSeparatedByString:@"\""] count] > 1) {
132 className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1];
133 // only decode if the property conforms to NSCoding
134 if (class_conformsToProtocol(NSClassFromString(className), @protocol(NSCoding))) {
135 value = [[coder decodeObjectForKey:key] retain];
136 addr = (NSInteger)&value;
137 object_setInstanceVariable(self, [key UTF8String], *(id**)addr);
142 number = [coder decodeObjectForKey:key];
143 b = [number boolValue];
144 addr = (NSInteger)&b;
145 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
148 number = [coder decodeObjectForKey:key];
149 f = [number floatValue];
150 addr = (NSInteger)&f;
151 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
154 number = [coder decodeObjectForKey:key];
155 d = [number doubleValue];
156 if ((ivar = class_getInstanceVariable([self class], [key UTF8String]))) {
157 varIndex = (double *)(void **)((char *)self + ivar_getOffset(ivar));
162 number = [coder decodeObjectForKey:key];
163 i = [number intValue];
164 addr = (NSInteger)&i;
165 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
167 case 'L': // unsigned long
168 number = [coder decodeObjectForKey:key];
169 ul = [number unsignedLongValue];
170 addr = (NSInteger)&ul;
171 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
173 case 'Q': // unsigned long long
174 number = [coder decodeObjectForKey:key];
175 ull = [number unsignedLongLongValue];
176 addr = (NSInteger)&ull;
177 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
185 - (NSInteger)intForKey:(NSString *)key inDict:(NSDictionary *)dict {
186 NSInteger result = 0;
187 if ([dict objectForKey:key] != [NSNull null]) {
188 result = [((NSNumber *)[dict objectForKey:key]) intValue];
193 - (void)autoParse:(NSObject **)object fromJSONDict:(NSDictionary *)dict {
194 NSDictionary *properties = [*object properties];
195 for (NSString *key in properties) {
199 NSString *type = [properties objectForKey:key];
200 SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [[key uppercaseString] substringToIndex:1], [key substringFromIndex:1]]);
202 NSMethodSignature *signature = [*object methodSignatureForSelector:setter];
203 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
204 [invocation setSelector:setter];
205 [invocation setTarget:*object];
207 switch ([type characterAtIndex:0]) {
209 if ([[type componentsSeparatedByString:@"\""] count] > 1) {
210 ///NSString *className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1];
211 [*object performSelector:setter withObject:[dict objectForKey:key]];
221 if ([dict objectForKey:key]) {
222 i = [*object intForKey:key inDict:dict];
223 [invocation setArgument:&i atIndex:2];
227 case 'L': // unsigned long
229 case 'Q': // unsigned long long