Objective c memory leak
Here are two methods that return a dictionary of my custom four-propery objects. They make arrays of strings, floats and BOOLs to put in the Chemical
objects, then build a dictionary from the arrays. I'm new enough to the whole memory management game that I'm not always sure when I own something and when to release it. I'm making all kinds of strings on the fly.
Here's the thing: The static analyzer sees no problem with the first method, - (id)generateChlorineDictionary
but says there's a leak in the second one, - (id)generateCYADictionary
. It says it starts at the NSMutableArray *cyaGranulesArray...
and then goes to NSDictionary *cyaDictionary...
and finally to the return cyaDictionary
statement.
Here are the two methods; sorry they're so long!
EDIT: Changed name from generateChlorineDictionary to newChlorineDictionary
Removed a release that happened after the return- (id)newChlorineDictionary {
// Sets up the array for the Bleach key
NSMutableArray *bleachArray = [[NSMutableArray alloc] init];
NSArray *bleachConcentrationArray = [[NSArray alloc] initWithObjects:@"6%", @"10%", @"12%", nil];
float bleachConstantArray[] = {0.0021400, 0.0012840, 0.0010700};
for (int i=0; i<3; i++) {
Chemical *bleachChemical = [[Chemical alloc] initWithChemical:@"Bleach"
andConcentration:[bleachConcentrationArray objectAtIndex:i]
andConstant:bleachConstantArray[i]
andIsLiquid:YES];
[bleachArray addObject:bleachChemical];
NSLog(@"bleachChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", bleachChemical.chemName, bleachChemical.chemConcentration, bleachChemical.chemConstant, bleachChemical.chemIsLiquid);
[bleachChemical release];
}
bleachConcentrationArray = nil;
// Sets up the array for the Trichlor key
NSMutableArray *trichlorArray = [[NSMutableArray alloc] init];
Chemical *trichlorChemical = [[Chemical alloc] initWithChemical:@"Trichlor"
andConcentration:@"90%"
andConstant:0.0001480
andIsLiquid:NO];
[trichlorArray addObject:trichlorChemical];
NSLog(@"trichlorChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", trichlorChemical.chemName, trichlorChemical.chemConcentration, trichlorChemical.chemConstant, trichlorChemical.chemIsLiquid);
[trichlorChemical release];
// Sets up the array for the Dichlor key
NSMutableArray *dichlorArray = [[NSMutableArray alloc] init];
NSArray *dichlorConcentrationArray = [[NSArray alloc] initWithObjects:@"56%", @"62%", nil];
float dichlorConstantArray[] = {0.0002400, 0.0002168};
for (int i=0开发者_如何学Go; i<2; i++) {
Chemical *dichlorChemical = [[Chemical alloc] initWithChemical:@"Dichlor"
andConcentration:[dichlorConcentrationArray objectAtIndex:i]
andConstant:dichlorConstantArray[i]
andIsLiquid:NO];
[dichlorArray addObject:dichlorChemical];
NSLog(@"dichlorChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", dichlorChemical.chemName, dichlorChemical.chemConcentration, dichlorChemical.chemConstant, dichlorChemical.chemIsLiquid);
[dichlorChemical release];
}
dichlorConcentrationArray = nil;
// Sets up the array for the Cal Hypo key
NSMutableArray *calHypoArray = [[NSMutableArray alloc] init];
NSArray *calHypoConcentrationArray = [[NSArray alloc] initWithObjects:@"48%", @"53%", @"65", @"73", nil];
float calHypoConstantArray[] = {0.0002817, 0.0002551, 0.0002080, 0.0001852};
for (int i=0; i<2; i++) {
Chemical *calHypoChemical = [[Chemical alloc] initWithChemical:@"Cal Hypo"
andConcentration:[calHypoConcentrationArray objectAtIndex:i]
andConstant:calHypoConstantArray[i]
andIsLiquid:NO];
[calHypoArray addObject:calHypoChemical];
NSLog(@"calHypoChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", calHypoChemical.chemName, calHypoChemical.chemConcentration, calHypoChemical.chemConstant, calHypoChemical.chemIsLiquid);
[calHypoChemical release];
}
calHypoConcentrationArray = nil;
// Sets up the array for the Li Hypo key
NSMutableArray *liHypoArray = [[NSMutableArray alloc] init];
Chemical *liHypoChemical = [[Chemical alloc] initWithChemical:@"Li Hypo"
andConcentration:@"90%"
andConstant:0.0003800
andIsLiquid:NO];
[liHypoArray addObject:liHypoChemical];
NSLog(@"liHypoChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", liHypoChemical.chemName, liHypoChemical.chemConcentration, liHypoChemical.chemConstant, liHypoChemical.chemIsLiquid);
[liHypoChemical release];
// The array of keys for the chlorine chemicals
NSArray *chlorineKeys = [[NSArray alloc] initWithObjects:@"Bleach", @"Trichlor", @"Dichlor", @"Cal Hypo", @"Li Hypo", nil];
// The array of values for the chlorine chemicals
NSArray *chlorineValues = [[NSArray alloc] initWithObjects:bleachArray, trichlorArray, dichlorArray, calHypoArray, liHypoArray, nil];
[bleachArray release];
[trichlorArray release];
[dichlorArray release];
[calHypoArray release];
[liHypoArray release];
// The dictionary to hold the arrays of chlorine chemical objects
NSDictionary *chlorineDictionary = [[NSDictionary alloc] initWithObjects:chlorineValues forKeys:chlorineKeys];
[chlorineValues release];
[chlorineKeys release];
return chlorineDictionary;
}
EDIT: Changed name from generateCYADictionary to newCYADictionary
Removed a release that happened after the return- (id)newCYADictionary {
// Sets up the array for the CYA Granules key
NSMutableArray *cyaGranulesArray = [[NSMutableArray alloc] init];
Chemical *cyaGranulesChemical = [[Chemical alloc] initWithChemical:@"CYA Granules"
andConcentration:@""
andConstant:0.0001330
andIsLiquid:NO];
[cyaGranulesArray addObject:cyaGranulesChemical];
NSLog(@"cyaGranulesChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", cyaGranulesChemical.chemName, cyaGranulesChemical.chemConcentration, cyaGranulesChemical.chemConstant, cyaGranulesChemical.chemIsLiquid);
[cyaGranulesChemical release];
// Sets up the array for the Liquid Stabilizer key
NSMutableArray *liquidStabilizerArray = [[NSMutableArray alloc] init];
Chemical *liquidStabilizerChemical = [[Chemical alloc] initWithChemical:@"Liquid Stabilizer"
andConcentration:@""
andConstant:0.0003460
andIsLiquid:YES];
[liquidStabilizerArray addObject:liquidStabilizerChemical];
NSLog(@"liquidStabilizerChemical: chemName = %@, chemConcentration = %@, chemConstant = %1.6f, chemIsLiquid = %d", liquidStabilizerChemical.chemName, liquidStabilizerChemical.chemConcentration, liquidStabilizerChemical.chemConstant, liquidStabilizerChemical.chemIsLiquid);
[liquidStabilizerChemical release];
// The array of keys for the CYA chemicals
NSArray *cyaKeys = [[NSArray alloc] initWithObjects:@"CYA Granules", @"Liquid Stabilizer", nil];
// The array of values for the CYA chemicals
NSArray *cyaValues = [[NSArray alloc] initWithObjects:cyaGranulesArray, liquidStabilizerArray, nil];
[cyaGranulesArray release];
[liquidStabilizerArray release];
// The dictionary to hold the arrays of CYA chemical objects
NSDictionary *cyaDictionary = [[NSDictionary alloc] initWithObjects:cyaValues forKeys:cyaKeys];
[cyaKeys release];
[cyaValues release];
return cyaDictionary;
}
Replace the
return cyaDictionary;
[cyaDictionary release];
With
return [cyaDictionary autorelease];
Or, you might replace the
NSDictionary *chlorineDictionary = [[NSDictionary alloc] initWithObjects:chlorineValues forKeys:chlorineKeys];
With
NSDictionary *chlorineDictionary = [NSDictionary dictionaryWithObjects:chlorineValues forKeys:chlorineKeys];
Instead of adding the autorelease
.
In your original implementation the [cyaDictionary release];
is never executed (because it is after return
).
You can use this dictionary outside this method and you shouldn't release it there.
You might want also return a retained object (without the autorelease
) and release it outside the method. In this case you should start the method name with "new" or "alloc"...
EDIT (Important):
You should use only one of my suggestions.
- Use the
autorelease
in thereturn
line - Use the
dictionaryWith...
- Add the "new" or "alloc" prefix in the method name and release the returned object outside this method.
If you replace the alloc init
with dictionaryWith...
then you get an autoreleased object. And then, if you release it in the outer method then you have a serious problem (the object will try to release itself after the current runloop of the thread and it may crash the app because the object will already be released by you).
EDIT (due to one of the comments)
If you want to create a property that will return a dictionary:
// MyClass.h file
@interface MyClass : NSObject {
..
NSDictionary *_dict1;
..
}
@property (nonatomic, retain) NSDictionary *dict1;
..
@end
// MyClass.m file
@implementation MyClass
@synthesize dict1 = _dict1;
..
- (NSDictionary *)dict1 {
if (_dict1 == nil) {
NSDictionary *dict1Temp = [NSDictionary new];
// Your implementation goes here...
self.dict1 = dict1Temp;
[dict1Temp release];
}
}
..
- (void)dealloc {
[_dict1 release];
[suoer dealloc];
}
@end
精彩评论