tags:

views:

37

answers:

3

Hi, please go through the following code and please explain why is it crashes in last line?

NSMutableDictionary *dic1 = [[NSMutableDictionary alloc] initWithCapacity:10];
NSString *val = [[NSString alloc] initWithFormat:@"Deepak"];
NSString *key = [[NSString alloc] initWithFormat:@"First Name"];    

int a = [val retainCount];
a = [key retainCount];

[dic1 setObject:val forKey:key];
a = [val retainCount];
a = [key retainCount];

//self.mainDic = [dic1 copy];
self.mainDic = [dic1 mutableCopy];//mainDic is like @property(copy) NSMutableDictionary *
[self.mainDic setObject:@"Hi" forKey:@"Good"];//Problem

Thanks.

+2  A: 

copy properties are not suitable for mutable classes as they don't respect mutability and just send the copy message to the instances - what happens in the second last line is basically:

// ... release previous mainDic, if any
mainDic = [[dic1 mutableCopy] copy];

As the copy message results in an immutable version, NSDictionary, you are probably getting exception for an unrecognized selector -setObject:forKey: while debugging.

If you want to use copy properties you should provide your own setter instead and remove that manual mutableCopy - see e.g. Apples docs on the copy semantics.

Georg Fritzsche
+1  A: 

I've almost never used a property with a modifier other than (nonatomic, retain) this has saved me of a lot of problems, that and on the dealloc method set'em to nil

this is the way I'd do it

NSMutableDictionary *dic1 = [[NSMutableDictionary alloc] initWithCapacity:10];

NSString *val = [[NSString alloc] initWithFormat:@"Deepak"]; 
NSString *key = [[NSString alloc] initWithFormat:@"First Name"];    

[dic1 setObject:val forKey:key];

self.mainDic = dic1; //where mainDic is like @property (nonatomic, retain) NSMutableDictionary *

[self.mainDic setObject:@"Hi" forKey:@"Good"];

//let's clean this mess up 
[val release]; 
[key release]; 
[dic1 release];
camilin87
Now what if object in question comes from outside of the class and gets changed from outside later, thus breaking encapsulation? See e.g. the first part of the [copy section](http://developer.apple.com/mac/library/documentation/cocoa/conceptual/objectivec/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW32) in the docs.
Georg Fritzsche
I'm just saying I've never used copy, in those cases -keeping an object in my class that can change outside, where I still want to keep the outdated copy- I've managed to make a Clone method myself, I came from C# so I'm uncomfortable using copy.
camilin87
It's recommended that you don't use properties in dealloc. Instead of setting the properties to nil, you should release the inst vars.
JeremyP
But `copy` is exactly for those cases and clearly communicates what behavior to expect. Its only that with mutable classes as `copy` properties a custom setter is needed.
Georg Fritzsche
A: 

@Deepak ! your code itself works well. And there is no static analysis erro except un-referring a and memory leaking of dic1.

self.mainDic = [dic1 mutableCopy]; works well. Please run your code block again. I created a new project and put your code and tested it. There was no problem.

@Georg Fritzsche your code is making crash.

alones
What code? I only said *"with your code there is something like this happening"*.
Georg Fritzsche
@Georg Fritzsche When I ran @Deepak's code after putting your following code, crash occurred.mainDic = [[dic1 mutableCopy] copy];
alones
**I didn't say to use that code** ... it was an example of what the effects of a `copy` property are. Let me guess, you tested with a `retain` or `assign` property for `mainDic`? In that case you wouldn't have the problem the OP was having.
Georg Fritzsche