When using Clang static analyzer to analyze my Objective-C code for iOS, I get lots of "potential leaks". Many of the leaks make me wonder why it's erroneous at all. One example that left me wondering in particular was the following:
I have a class-variable of type NSDictionary
, used for storing some settings. Now when I have a method to change something inside the dictionary:
- (void) loadPassengerCompartiments {
NSMutableArray *paxCompartiments = [self.outputTable objectAtIndex:2];
NSArray *paxCompSrc = [self.values objectForKe开发者_Go百科y:@"PassengerCompartiments"];
for(MassPerson *passenger in paxCompSrc) {
=> [paxCompartiments addObject:[[PaxCompartimentOutputField alloc] initWithPerson:passenger]];
}
}
Clang errs at the in-line allocation and direct association of PaxCompartimentOutputField
.
When running this code in instruments it doesn't leak.
Two ways I could come up with to solve this are:
- use
autorelease
- replace the in-line allocation with the following code:
(code)
PaxCompartimentOutputField *field = [[PaxCompartimentOutputField alloc] initWithPerson:passenger];
[paxCompartiments addObject:field];
[field release];
The first option is obsolete imho (and especially on iOS its use is discouraged) The second option is pretty bulky - especially when creating an array with more objects (say 10 objects loading default settings).
I don't want to ignore Clang's warnings, as it is an excellent tool for finding bugs & leaks. What is the 'right' way to do this in Objective-C for those cases?
That is a leak.
Since you alloc-init PaxCompartimentOutputField
, you own it and you must relinquish ownership of it.
You have 3 options (you already mentioned 2 of them):
1) Use a convenience constructor, when one is available, or in a custom class, declare one. Convenience constructors return objects you do not own, typically by sending an autorelease
message to the object they return. It would look like this:
[paxCompartiments addObject:[PaxCompartimentOutputField paxCompartimentOutputWithPerson:passenger]];
2) Use autorelease
.
[paxCompartiments addObject:[[[PaxCompartimentOutputField alloc] initWithPerson:passenger]] autorelease];
3) Use a temporary variable.
PaxCompartimentOutputField *tempField = [[PaxCompartimentOutputField alloc] initWithPerson:passenger];
[paxCompartiments addObject:tempField];
[tempField release];
There is a list of source annotations that you can use with Clang.
These might help.
精彩评论