Deep combine NSDictionaries

Viewed 11366

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.

8 Answers

I needed a way to recursively merge (append) objects within two JSON objects, focusing on the NSDictionaries within, but also considering NSArrays, and gracefully handling when types don't match along the way. The other answers here didn't go that far, and so I needed to write it myself. The following handles all those cases. Because the validation is at the top rather than in the middle it is usable starting with mixed nonnull and nullable objects. It could be expanded in the future to support additional types where appending may apply. To use, rename the xxx_ prefix to your own three digit prefix in lowercase. This is appropriate since this is an extension to a foundation class:

NSObject+Append.h

@interface NSObject (Append)

+ (nullable id)xxx_objectAppendingObject1:(nullable id)object1 object2:(nullable id)object2 NS_SWIFT_NAME(kva_objectAppending(object1:object2:));


@end

NSObject+Append.m

@implementation NSObject (Append)


+ (nullable id)xxx_objectAppendingObject1:(nullable id)object1 object2:(nullable id)object2
{
    // VALIDATE ELSE RETURN
    if (object1 == nil)
    {
        return object2;
    }

    if (object2 == nil)
    {
        return object1;
    }

    // MAIN
    // dictionary1
    NSDictionary *dictionary1 = [object1 isKindOfClass:NSDictionary.class] ? (NSDictionary *)object1 : nil;
    
    // dictionary2
    NSDictionary *dictionary2 = [object2 isKindOfClass:NSDictionary.class] ? (NSDictionary *)object2 : nil;
    
    // array1
    NSArray *array1 = [object1 isKindOfClass:NSArray.class] ? (NSArray *)object1 : nil;
    
    // array2
    NSArray *array2 = [object2 isKindOfClass:NSArray.class] ? (NSArray *)object2 : nil;
    
    // A. NSDICTIONARY TO NSDICTIONARY
    if ((dictionary1 != nil) && (dictionary2 != nil))
    {
        NSMutableDictionary *returnDictionary = dictionary1.mutableCopy;
        [dictionary2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop)
        {
            returnDictionary[key] = [self.class kva_objectAppendingObject1:dictionary1[key] object2:obj];
        }];
        return returnDictionary;
    }

    // B. NSARRAY TO NSARRAY
    if ((array1 != nil) && (array2 != nil))
    {
        return [array1.mutableCopy arrayByAddingObjectsFromArray:array2];
    }

    // DEFAULT
    return object2;
}

@end
Related