Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

deep mutable copy of a NSMutableDictionary

I am trying to create a deep-copy of a NSMutableDictionary and assign it to another NSMutableDictionary. The dictionary contains a bunch of arrays, each array containing names, and the key is an alphabet (the first letter of those names). So one entry in the dictionary is 'A' -> 'Adam', 'Apple'. Here's what I saw in a book, but I'm not sure if it works:

- (NSMutableDictionary *) mutableDeepCopy
{
    NSMutableDictionary * ret = [[NSMutableDictionary alloc] initWithCapacity: [self count]];
    NSArray *keys = [self allKeys];

    for (id key in keys)
    {
        id oneValue = [self valueForKey:key]; // should return the array
        id oneCopy = nil;

        if ([oneValue respondsToSelector: @selector(mutableDeepCopy)])
        {
            oneCopy = [oneValue mutableDeepCopy];
        }
        if ([oneValue respondsToSelector:@selector(mutableCopy)])
        {
            oneCopy = [oneValue mutableCopy];
        }

        if (oneCopy == nil) // not sure if this is needed
        {   
            oneCopy = [oneValue copy];
        }
        [ret setValue:oneCopy forKey:key];

        //[oneCopy release];
    }
    return ret;
}
  • should the [onecopy release] be there or not?
  • Here's how I'm going to call this method:

    self.namesForAlphabets = [self.allNames mutableDeepCopy];

Will that be ok? Or will it cause a leak? (assume that I declare self.namesForAlphabets as a property, and release it in dealloc).

like image 349
Z S Avatar asked Dec 23 '09 02:12

Z S


3 Answers

Because of toll-free bridging, you can also use the CoreFoundation function CFPropertyListCreateDeepCopy:

NSMutableDictionary *mutableCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);
like image 55
Wevah Avatar answered Nov 20 '22 08:11

Wevah


Assuming all elements of the array implement the NSCoding protocol, you can do deep copies via archiving because archiving will preserve the mutability of objects.

Something like this:

id DeepCopyViaArchiving(id<NSCoding> anObject)
{
    NSData* archivedData = [NSKeyedArchiver archivedDataWithRootObject:anObject];
    return [[NSKeyedUnarchiver unarchiveObjectWithData:archivedData] retain];
}

This isn't particularly efficient, though.

like image 12
Tom Dalling Avatar answered Nov 20 '22 08:11

Tom Dalling


Another technique that I have seen (which is not at all very efficient) is to use an NSPropertyListSerialization object to serialise your dictionary, then you de-serialise it but specify that you want mutable leaves and containers.


NSString *errorString = nil;
NSData *binData = 
  [NSPropertyListSerialization dataFromPropertyList:self.allNames
                                             format:NSPropertyListBinaryFormat_v1_0
                                        errorString:&errorString];

if (errorString) {
    // Something bad happened
    [errorString release];
}

self.namesForAlphabets = 
 [NSPropertyListSerialization propertyListFromData:binData
                                  mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                            format:NULL
                                  errorDescription:&errorString];

if (errorString) {
    // something bad happened
    [errorString release];
}

Again, this is not at all efficient.

like image 10
dreamlax Avatar answered Nov 20 '22 10:11

dreamlax