0

In my code, I define a NSDictionary in viewDidAppear like this:

dataDictionary = [[NSMutableDictionary alloc] init];

then later in a loadData method, I load a mutable copy of the NSDictionary like this:

      [dataDictionary setObject:[receivedData mutableCopy] forKey:[theConnection description]];

Later, when I switch to a different view, I unload my dataDictionary to save memory. In viewDidDissappear, I put:

[dataDictionary release]; dataDictionary=nil;

and I also release dataDictionary in dealloc.

However, it seems that there is a memory leak related to mutableCopy, and this is the only mutableCopy that I make, so it must be from the mutableCopy shown above. Does anybody have any idea why this might be leaking? I am thinking that mutableCopy makes another allocation besides the allocation made for the NSMutableDictionary, but I'm not sure how to deal with that since the mutableCopy is inside the dictionary and the dictionary is released.

Thanks in advance...

Jackson
  • 3,555
  • 3
  • 34
  • 50
  • it looks fine, you need to `[receivedData release]` if you are no longer using `receivedData`, otherwise atleast release `receivedData` in dealloc – Waqas Raja Mar 17 '11 at 14:51
  • Yep I did release receivedData after I added it to the dictionary as a copy... – Jackson Mar 17 '11 at 14:58

3 Answers3

4

the mutableCopy method is not returning an autoreleased object, so you're receiving your NSMutableData with a retain count of 1, then you add it to the dictionary which also retains it - which means it will not be destroyed when you remove it from the dictionary or when the dictionary is dealloced, you will lose any reference to it, and the object will be leaked.

so like someone else suggested, autorelease the mutable copy when adding it to the dataDictionary.

[dataDictionary setObject:[[receivedData mutableCopy] autorelease] forKey:[theConnection description]];

or do something like

NSMutableData *mutableData = [receivedData mutableCopy];
[dataDictionary setObject:mutableData forKey:[theConnection description]];
[mutableData release];
Zaky German
  • 14,324
  • 4
  • 25
  • 31
  • I tried the second option but I still get the leak. After looking more carefully the leak isn't specifically NSMutableData but NSConcreteMutableData. Does the fact that it says concrete mean anything to you that might help me make sense of this leak? – Jackson Mar 17 '11 at 19:38
2

Try something like this

[dataDictionary setObject:[[receivedData mutableCopy] autorelease] forKey:[theConnection description]];
Nyx0uf
  • 4,609
  • 1
  • 25
  • 26
  • That seems to cause a crash and "malloc: *** error for object 0x5e3cbd0: double free" error when I later try to remove one of the objects from dataDictionary. – Jackson Mar 17 '11 at 15:00
0

Like Benj and Zaky already mentioned, you should call autorelease on your mutableCopy, but you also have to make sure not to release dataDictionary in both dealloc and viewDidDisappear:. Since dataDictionary has a retain count of 1 when you create it, and both viewDidDisappear: and dealloc probably get invoked when your view is destroyed, you'll wind up trying to release an object that's already been freed.

Make sure you only release dataDictionary in dealloc and you won't see the "double free" error message you mentioned. Invoking "release" on an ivar in viewDidDisappear: is a risky proposition anyway, since viewDidDisappear: gets invoked multiple times throughout the lifecycle of a view (e.g., if other view controllers get pushed onto your navigation stack). If you want to make sure to save memory, it's best to create stuff in viewDidLoad and to release stuff in viewDidUnload. viewDidUnload gets called in low-memory situations, so it's exactly what you want in this situation.

You may want to check out this post for a detailed description about Cocoa reference counting conventions: Object ownership in stringWithString and initWithString in NSString

Community
  • 1
  • 1
Joshua Pokotilow
  • 1,213
  • 9
  • 13