tags:

views:

58

answers:

3

Hi,

Is there a way to convert mutable object converted to immutable one in cocoa? I have used NSMutableDictionary *mut=[[NSMutableDictionary alloc] initWithDictionary: copyItems:]; But this dictionary is used in many other places without the mutable thing.

Best Regards, Subrat

+3  A: 

NSDictionary dictionaryWithDictionary:

Amorya
or `[myDictionary copy]`
Mike Abdullah
OK let me pour in more details. I have a list of NSMutableDictionary. I am copying a NSMUtableDictinary and putting it in the list as a new entry. But whenever I do some changes in the copied one, the changes are reflected in the original one too. For this tried using NSMutableDictionary *mut=[[NSMutableDictionary alloc] initWithDictionary: copyItems:]; But this too does not work. Once the dictinary is copied, I am unable to perform operation on one of the values of the dictianry later because of mutable to immutable conversion thing. Is there any way out?
Subrat
A: 

If I understand your question correctly (given your later comment), you want to convert an immutable copy of an mutable object back to being mutable again.

The problem seems to be this:

NSMutableString *foo = [NSMutableString stringWithString:@"a mutable object"];

NSMutableDictionary *dictionary1, *dictionary2;

dictionary1 = [NSMutableDictionary dictionaryWithObject:foo forKey:@"foo"];
dictionary2 = [[NSMutableDictionary alloc]initWithDictionary:dictionary1
               copyItems: YES];

[[dictionary1 objectForKey:@"foo"] appendString:@", mutated"];
[[dictionary2 objectForKey:@"foo"] appendString:@", mutated"];

we can alter the object in dictionary1 just fine, but doing the same to dictionary2 throws an exception.

This is because although NSMutableDictionary's initWithDictionary:copyItems: method makes a mutable copy of the dictionary object, it makes immutable copies of its contents.

Classes that distinguish between immutable and immutable versions (such as cocoa's basic string, array & dictionary classes) are supposed to implement a copyWithZone: and mutableCopyWithZone: method. Since not all classes implement an mutableCopyWithZone: method, NSMutableDictionary's initWithDictionary:copyItems: method copies each of dictionary1's contents immutably, meaning that dictionary2 contains immutable objects.

You can make an mutable copy of an immutable object by sending it a mutableCopy message. But probably a better solution for you would be to add an initWithDictionary:mutableCopyItems: method to NSMutableDictionary with a category:

- (id) initWithDictionary:(NSDictionary *)otherDictionary
      mutableCopyItems:(BOOL)flag
{
 if (flag) {
  self = [self init];

  if (self)
   for (id key in otherDictionary){
    id object = [otherDictionary objectForKey:key];
    if ([object respondsToSelector:@selector(mutableCopyWithZone:)])
     [self setObject:[object mutableCopy] forKey:key];
    else
     [self setObject:[object copy] forKey:key];
   }
 }
 else
  self = [self initWithDictionary:otherDictionary];

 return self;
}

Read these if you want to know the difference between copy, mutableCopy, copyWithZone: and mutableCopyWithZone:

http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Protocols/NSMutableCopying_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSMutableCopying

http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Protocols/NSCopying_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSCopying

Chris Devereux
A: 

This may be an overly simplistic answer, but:

NSMutableDictionary * mutableDictionary = [NSMutableDictionary dictionaryWithStuff....];
NSDictionary * dictionary = mutableDictionary;
//from this point on, only use dictionary

While dictionary is technically (internally) mutable, you won't be able to access the set methods, since those are methods on NSMutableDictionary.

Dave DeLong