Can't Figure Out How To Fix Memory Leaks on iPhone
I was running Leaks tool and discovered a massive leak in my 开发者_高级运维Dictionary mutableDeepCopy but I can't figure out what's wrong with the code. Any suggestions?
@interface RootViewController : UIViewController{
NSDictionary *immutableDictionary;
NSMutableDictionary *mutableDictionary;
}
Here is the line of code that's highlighted in Instruments
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
Here is the method for creating a mutable copy of a Dictionary
@interface NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy;
@end
Here is method implementation, I've highlighted the code that Leaks saids is leaking 100%
- (NSMutableDictionary *) mutableDeepCopy {
NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for(id key in keys) {
id value = [self valueForKey:key];
id copy = nil;
if ([value respondsToSelector:@selector(mutableDeepCopy)]) {
copy = [value mutableDeepCopy];
} else if ([value respondsToSelector:@selector(mutableCopy)]) {
copy = [value mutableCopy]; //This is the Leak
}
if (copy == nil) {
copy = [value copy];
}
[dictionaryToReturn setValue:copy forKey:key];
}
return dictionaryToReturn;
}
You need to analyse this in light of Apple's Memory Management Rules.
Starting with this line:
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
I would expect mutableDeepCopy to return an object I own, so at some point I need to release or autorelease it. e.g.
NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy];
self.mutableDictionary = temp;
[temp release];
or
self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease];
So now we need to look at mutableDeepCopy. Because it has 'copy' in the name it needs to returned an "owned" object which, in practice means "forgetting" to release the returned object. You have already failed to do that when you create the returned object in the first line, since dictionaryWithCapacity: gives you an object you do not own. Replace it with
NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
Now you own it.
It is important that you make your mutableDeepCopy obey the rules because it means you can treat the objects returned from mutableDeepCopy, mutableCopy and copy in exactly the same way. In all three cases you own the object copy that you insert into the array. Because you own it, you must release it or it'll leak as you found out. So, at the end of the loop, you need
[copy release];
That'll stop the leak.
How is your property declared? If is is retain
or copy
, then this doesn't leak.
Your problem is that the name mutableDeepCopy
suggests that it returns a retained object, and not an autoreleased one as it actually does.
Edit:
And at the mutableDeepCopy itself, you need to release the copy
variable after adding to the dictionary.
mutableCopy
increments the retain count of the object, as does setValue:forKey:
. This means that when dictionaryToReturn
is dealloc'ed, the object that had mutableCopy
called still has a retain count of one.
Try doing this instead:
copy = [[value mutableCopy] autorelease];
精彩评论