36 votes

copie profonde mutable d'un NSMutableDictionary

Je suis en train de créer une copie en profondeur d'un NSMutableDictionary et de l'affecter à une autre NSMutableDictionary. Le dictionnaire contient un tas de tableaux, chaque tableau contenant les noms, et la clé est un alphabet (la première lettre de ces noms). Donc une entrée dans le dictionnaire de l'est 'A' -> 'Adam', 'Pomme'. Voici ce que j'ai vu dans un livre, mais je ne suis pas sûr si cela fonctionne:

- (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;
}
  • le [onecopy de presse] être là ou pas?
  • Voici comment je vais faire appel de cette méthode:

    auto.namesForAlphabets = [self.allNames mutableDeepCopy];

Est-ce ok? Ou sera-ce la cause d'une fuite? (supposons que je déclare de soi.namesForAlphabets comme une propriété, et de le libérer dans le dealloc).

75voto

Wevah Points 17636

Grâce au pontage sans frais, vous pouvez également utiliser la fonction CoreFoundation CFPropertyListCreateDeepCopy :

 NSMutableDictionary *mutableCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);
 

11voto

Tom Dalling Points 10656

En supposant que tous les éléments de la matrice implémentent le protocole NSCoding, vous pouvez effectuer des copies complètes via l'archivage, car l'archivage préservera la mutabilité des objets.

Quelque chose comme ça:

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

Ce n'est pas particulièrement efficace, cependant.

9voto

dreamlax Points 47152

Une autre technique que j’ai vue (ce qui n’est pas du tout très efficace) consiste à utiliser un objet NSPropertyListSerialization pour sérialiser votre dictionnaire, puis vous le désérialiser, mais vous indiquez que vous souhaitez des feuilles et des conteneurs mutables.

 
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];
}
 

Encore une fois, ce n'est pas du tout efficace.

9voto

e.James Points 51680

IMPORTANT: La question (et mon code ci-dessous) à traiter un cas très spécifique, dans lequel le NSMutableDictionary contient uniquement des tableaux de chaînes de caractères. Ces solutions ne fonctionnera pas pour des exemples plus complexes. Pour le cas plus général des solutions, voir les rubriques suivantes:


Réponse pour ce cas précis:

Votre code devrait fonctionner, mais vous aurez certainement besoin de l' [oneCopy release]. Le nouveau dictionnaire de conserver les objets copiés lorsque vous les ajoutez à setValue:forKey, donc si vous n'appelez pas [oneCopy release], l'ensemble de ces objets seront conservés deux fois.

Une bonne règle de base: si vous alloc, retain ou copy de quelque chose, vous devez également release il.

Note: voici un exemple de code qui fonctionne pour certains cas seulement. Cela fonctionne parce que votre NSMutableDictionary contient uniquement les tableaux de chaînes de caractères (pas plus profonde de la copie obligatoire):

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

    NSMutableArray * array;

    for (id key in [self allKeys])
    {
        array = [(NSArray *)[self objectForKey:key] mutableCopy];
        [ret setValue:array forKey:key];
        [array release];
    }

    return ret;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X