Potential leak of an object warning -- clarification needed
After I Analyzed my code, Xcode indicated a potential leak as shown below.
Is this something I should be concerned about?
In this code, the class that sets doublyLinkedList
is the sole owner and continues to开发者_StackOverflow manage this object throughout program execution.
The reason you're getting the warning is because the new
call returns a retained object, and then your setter is probably doing another retain
on it (depends on whether it's synthesized or manually generated).
Also, I would recommend you use the standard alloc
/init
instead of new
, so that the two-phase creation is obvious.
This is better:
if (self) {
DoublyLinkedList *dll = [[[DoublyLinkedList alloc] init] autorelease];
self.doublyLinkedList = dll;
}
or just
if (self) {
self.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease];
}
You may wish to do this instead:
if (self) {
DoublyLinkedList *dll = [DoublyLinkedList new];
self.doublyLinkedList = dll;
[dll release];
}
In the header, declare doublyLinkedList a @property
that is retained.
You have a "potential leak" because the Analyzer sees that you have allocated memory for a DoublyLinkedList
instance (using new
), put it into a local variable called dll
, and not released that memory in the same scope.
Assuming that the doublyLinkedList
member that you're setting happens to also be a property declared as retain
ing, you also have an actual leak, because you have over-retained the DoublyLinkedList
that you create here.
The ownership rules say that you have one claim on this instance because you called new
to create it. When you pass the instance to setDoublyLinkedList:
, it is retained, and you then have two claims. When the init
method ends, you only have one reference to the instance, through the ivar/property -- you've lost the local variable -- which means that you have more ownership claims than you have references. This is a good indication that you will have a leak.
To fix the leak, you need to relinquish one of your claims before the end of the init
method. You can do this in one of two ways, using release
as soon as the property is set:
DoublyLinkedList * dll = [DoublyLinkedList new];
[self setDoublyLinkedList:dll];
[dll release];
or autorelease
:
[self setDoublyLinkedList:[[DoublyLinkedList new] autorelease]];
// Or equivalent procedures involving a temp variable
However, it should be noted that using setters in init
may be problematic (see also Mike Ash's writeup on the topic), because accessors can -- potentially -- have side effects that depend on your object already being fully set up. There seem to be two camps on this issue, and it's probably best to read about it and come to your own conclusions, but you may find that it simplifies your initializer methods to assign to ivars rather than using properties:
if( self ){
doublyLinkedList = [DoublyLinkedList new];
}
This is completely correct in terms of memory management.
Finally, if DoublyLinkedList
is a class whose code you have, you can also consider writing a convenience constructor, which will return a new, autoreleased instance for you. The convention in Cocoa is to simply name the method after the class, with standard method name casing, like so:
+ (id) doublyLinkedList {
return [[[self alloc] init] autorelease];
}
Note that this is a class method:
if( self ){
[self setDoublyLinkedList:[DoublyLinkedList doublyLinkedList]];
}
and see my answer to "Self-allocating objects" for an explanation of these constructors.
If you have a property called "doublyLinkedList" (assumption based on code given), and it is "retained," you can do the following:
if (self) {
DoublyLinkedList *dll = [[DoublyLinkedList alloc] init]
self.doublyLinkedList = dll;
[dll release];
}
精彩评论