how to do true deep copy for NSArray and NSDictionary with have nested arrays/dictionary?

后端 未结 4 1938
一整个雨季
一整个雨季 2020-11-27 03:36

Question: Is there a way to use existing objective-c methods to do a full deep copy of a NSDictionary or NSArray, that themselves have nested dictionaries or arrays within t

相关标签:
4条回答
  • 2020-11-27 04:06

    I think something like this should work.

    NSData *buffer;
    NSMutableDictionary *_dict1, *_dict2;
    
    // Deep copy "all" objects in _dict1 pointers and all to _dict2  
    buffer = [NSKeyedArchiver archivedDataWithRootObject: _dict1];  
    _dict2 = [NSKeyedUnarchiver unarchiveObjectWithData: buffer];  
    
    0 讨论(0)
  • 2020-11-27 04:16

    If someone want the mutable copy then please use below code:

    NSMutableDictionary *newDictionary = (NSMutableDictionary *)CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)dict, kCFPropertyListMutableContainers));

    0 讨论(0)
  • A couple of years ago, I wrote a few category methods for exactly the same reason, transforming a whole tree of user defaults to mutable. Here they are - use them at your own risk! :-)

    //
    //  SPDeepCopy.h
    //
    //  Created by Sherm Pendley on 3/15/09.
    //
    
    #import <Cocoa/Cocoa.h>
    
    // Deep -copy and -mutableCopy methods for NSArray and NSDictionary
    
    @interface NSArray (SPDeepCopy)
    
    - (NSArray*) deepCopy;
    - (NSMutableArray*) mutableDeepCopy;
    
    @end
    
    @interface NSDictionary (SPDeepCopy)
    
    - (NSDictionary*) deepCopy;
    - (NSMutableDictionary*) mutableDeepCopy;
    
    @end
    

    //
    //  SPDeepCopy.m
    //
    //  Created by Sherm Pendley on 3/15/09.
    //
    
    #import "SPDeepCopy.h"
    
    
    @implementation NSArray (SPDeepCopy)
    
    - (NSArray*) deepCopy {
        unsigned int count = [self count];
        id cArray[count];
    
        for (unsigned int i = 0; i < count; ++i) {
            id obj = [self objectAtIndex:i];
            if ([obj respondsToSelector:@selector(deepCopy)])
                cArray[i] = [obj deepCopy];
            else
                cArray[i] = [obj copy];
        }
    
        NSArray *ret = [[NSArray arrayWithObjects:cArray count:count] retain];
    
        // The newly-created array retained these, so now we need to balance the above copies
        for (unsigned int i = 0; i < count; ++i)
            [cArray[i] release];
    
        return ret;
    }
    - (NSMutableArray*) mutableDeepCopy {
        unsigned int count = [self count];
        id cArray[count];
    
        for (unsigned int i = 0; i < count; ++i) {
            id obj = [self objectAtIndex:i];
    
            // Try to do a deep mutable copy, if this object supports it
            if ([obj respondsToSelector:@selector(mutableDeepCopy)])
                cArray[i] = [obj mutableDeepCopy];
    
            // Then try a shallow mutable copy, if the object supports that
            else if ([obj respondsToSelector:@selector(mutableCopyWithZone:)])
                cArray[i] = [obj mutableCopy];
    
            // Next try to do a deep copy
            else if ([obj respondsToSelector:@selector(deepCopy)])
                cArray[i] = [obj deepCopy];
    
            // If all else fails, fall back to an ordinary copy
            else
                cArray[i] = [obj copy];
        }
    
        NSMutableArray *ret = [[NSMutableArray arrayWithObjects:cArray count:count] retain];
    
        // The newly-created array retained these, so now we need to balance the above copies
        for (unsigned int i = 0; i < count; ++i)
            [cArray[i] release];
    
        return ret;
    }
    
    @end
    
    @implementation NSDictionary (SPDeepCopy)
    
    - (NSDictionary*) deepCopy {
        unsigned int count = [self count];
        id cObjects[count];
        id cKeys[count];
    
        NSEnumerator *e = [self keyEnumerator];
        unsigned int i = 0;
        id thisKey;
        while ((thisKey = [e nextObject]) != nil) {
            id obj = [self objectForKey:thisKey];
    
            if ([obj respondsToSelector:@selector(deepCopy)])
                cObjects[i] = [obj deepCopy];
            else
                cObjects[i] = [obj copy];
    
            if ([thisKey respondsToSelector:@selector(deepCopy)])
                cKeys[i] = [thisKey deepCopy];
            else
                cKeys[i] = [thisKey copy];
    
            ++i;
        }
    
        NSDictionary *ret = [[NSDictionary dictionaryWithObjects:cObjects forKeys:cKeys count:count] retain];
    
        // The newly-created dictionary retained these, so now we need to balance the above copies
        for (unsigned int i = 0; i < count; ++i) {
            [cObjects[i] release];
            [cKeys[i] release];
        }
    
        return ret;
    }
    - (NSMutableDictionary*) mutableDeepCopy {
        unsigned int count = [self count];
        id cObjects[count];
        id cKeys[count];
    
        NSEnumerator *e = [self keyEnumerator];
        unsigned int i = 0;
        id thisKey;
        while ((thisKey = [e nextObject]) != nil) {
            id obj = [self objectForKey:thisKey];
    
            // Try to do a deep mutable copy, if this object supports it
            if ([obj respondsToSelector:@selector(mutableDeepCopy)])
                cObjects[i] = [obj mutableDeepCopy];
    
            // Then try a shallow mutable copy, if the object supports that
            else if ([obj respondsToSelector:@selector(mutableCopyWithZone:)])
                cObjects[i] = [obj mutableCopy];
    
            // Next try to do a deep copy
            else if ([obj respondsToSelector:@selector(deepCopy)])
                cObjects[i] = [obj deepCopy];
    
            // If all else fails, fall back to an ordinary copy
            else
                cObjects[i] = [obj copy];
    
            // I don't think mutable keys make much sense, so just do an ordinary copy
            if ([thisKey respondsToSelector:@selector(deepCopy)])
                cKeys[i] = [thisKey deepCopy];
            else
                cKeys[i] = [thisKey copy];
    
            ++i;
        }
    
        NSMutableDictionary *ret = [[NSMutableDictionary dictionaryWithObjects:cObjects forKeys:cKeys count:count] retain];
    
        // The newly-created dictionary retained these, so now we need to balance the above copies
        for (unsigned int i = 0; i < count; ++i) {
            [cObjects[i] release];
            [cKeys[i] release];
        }
    
        return ret;
    }
    
    @end
    
    0 讨论(0)
  • 2020-11-27 04:26

    The easy way for a DEEP copy is to simply use CFPropertyListCreateDeepCopy. Here is example (with ARC):

        NSDictionary *newDictionary =
     (__bridge NSDictionary *)(CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
             (__bridge CFPropertyListRef)(originalDictionary),
              kCFPropertyListImmutable));
    

    my originalDictionary in this example is an NSDictionary

    CFPropertyListRef can simply be cast to NSDictionary as long as the top level entity of the CFPropertyListRef is a CFDictionary.

    0 讨论(0)
提交回复
热议问题