views:

30

answers:

2

I need to merge two NSDictionarys into one provided that if there are dictionaries within the dictionaries, they are also merged.

More or less like jQuery's extend function.

+2  A: 

I think this is what you're looking for:

First, you need to make a deep mutable copy, so you can create a category on NSDictionary to do this:

@implementation NSDictionary (DeepCopy)

- (id)deepMutableCopy
{
    id copy(id obj) {
        id temp = [obj mutableCopy];
        if ( [temp isKindOfClass:[NSArray class]] ) {
            for ( int i = 0 ; i < [temp count] ; i++ )
                [temp replaceObjectAtIndex:i withObject:copy([temp objectAtIndex:i])];
        } else if ( [temp isKindOfClass:[NSDictionary class]] ) {
            NSEnumerator *enumerator = [temp keyEnumerator];
            NSString *nextKey;
            while (nextKey = [enumerator nextObject])
                [temp setObject:copy([temp objectForKey:nextKey]) forKey:nextKey];
        } 
        return temp;
    }

    return (copy(self));
}

@end

Then, you can call deepMutableCopy like this:

NSMutableDictionary *someDictionary = [someDict deepMutableCopy];
[someDictionary addEntriesFromDictionary:otherDictionary];
Jacob Relkin
And this is recursive? In that NSDictionaries in the NSDictionaries will also be merged?
Alexsander Akers
A: 

NSDictionary+Merge.h

#import <Foundation/Foundation.h>

@interface NSDictionary (Merge)

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2;
- (NSDictionary *) dictionaryByMergingWith: (NSDictionary *) dict;

@end

NSDictionary+Merge.m

#import "NSDictionary+Merge.h"

@implementation NSDictionary (Merge)

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
    NSMutableDictionary * result = [NSMutableDictionary dictionary];

    [dict2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
        if ([obj isKindOfClass: [NSDictionary class]] && [dict1 containsSomethingForKey: key]) {
            NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
            [result setObject: newVal forKey: key];
        } else if (![dict1 containsSomethingForKey: key]) {
            [result setObject: obj forKey: key];
        } else {
            [result setObject: [dict1 objectForKey: key] forKey: key];
        }
    }];

    return (NSDictionary *) [[result mutableCopy] autorelease];
}
- (NSDictionary *) dictionaryByMergingWith: (NSDictionary *) dict {
    return [[self class] dictionaryByMerging: self with: dict];
}

@end
Alexsander Akers