Instantiating Custom Class from NSDictionary

后端 未结 5 684
-上瘾入骨i
-上瘾入骨i 2021-01-30 09:45

I have a feeling that this is stupid question, but I\'ll ask anyway...

I have a collection of NSDictionary objects whose key/value pairs correspond to a cus

5条回答
  •  有刺的猬
    2021-01-30 10:05

    Just add category for NSObject for getting dictionaryRepresentation from your custom objects (in my case using in JSON serialization only):

    //  NSObject+JSONSerialize.h
    #import 
    
    @interface NSObject(JSONSerialize)
    
    - (NSDictionary *)dictionaryRepresentation;
    
    @end
    
    //  NSObject+JSONSerialize.m
    #import "NSObject+JSONSerialize.h"
    #import 
    
    @implementation NSObject(JSONSerialize)
    
    + (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary {
        return [[self alloc] initWithDictionary:aDictionary];
    }
    
    - (instancetype)initWithDictionary:(NSDictionary *)aDictionary {
        aDictionary = [aDictionary clean];
    
        self.isReady = NO;
    
        for (NSString* propName in [self allPropertyNames]) {
            [self setValue:aDictionary[propName] forKey:propName];
        }
    
        //You can add there some custom properties with wrong names like "id"
        //[self setValue:aDictionary[@"id"] forKeyPath:@"objectID"];
        self.isReady = YES;
    
        return self;
    }
    
    - (NSDictionary *)dictionaryRepresentation {
        NSMutableDictionary *result = [NSMutableDictionary dictionary];
        NSArray *propertyNames = [self allPropertyNames];
    
        id object;
        for (NSString *key in propertyNames) {
            object = [self valueForKey:key];
            if (object) {
                [result setObject:object forKey:key];
            }
        }
    
        return result;
    }
    
    - (NSArray *)allPropertyNames {
        unsigned count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
    
        NSMutableArray *rv = [NSMutableArray array];
    
        unsigned i;
        for (i = 0; i < count; i++) {
            objc_property_t property = properties[i];
            NSString *name = [NSString stringWithUTF8String:property_getName(property)];
            [rv addObject:name];
        }
        //You can add there some custom properties with wrong names like "id"
        //[rv addObject:@"objectID"];
        //Example use inside initWithDictionary:
        //[self setValue:aDictionary[@"id"] forKeyPath:@"objectID"];
    
        free(properties);
    
        return rv;
    }
    
    @end
    

    Also, you can see that my solution will not work with custom objects with nested objects or arrays. For Arrays - just change the lines of code in dictionaryRepresentation method:

        if (object) {
            if ([object isKindOfClass:[NSArray class]]) {
                @autoreleasepool {
                    NSMutableArray *array = [NSMutableArray array];
                    for (id item in (NSArray *)object) {
                        [array addObject:[item dictionaryRepresentation]];
                    }
    
                    [result setObject:array forKey:key];
                }
            } else {
                [result setObject:object forKey:key];
            }
        }
    

提交回复
热议问题