问题
I'm currently working through Apress's "Beginning iPhone 3 Development". A standard they use in their example applications is like the following code:
- (void)viewDidLoad {
BlueViewController *blueController = [[BlueViewController alloc]
initWithNibName:@"BlueView" bundle:nil];
self.blueViewController = blueController;
[self.view insertSubview:blueController.view atIndex:0];
[blueController release];
}
8.14.11 UPDATE (additional information)
blueViewController is declared as follows:
@property (retain, nonatomic) BlueViewController *blueViewController;
Whenever they perform an alloc
they put it in some temp variable (here blueController
) then they assign it, then they release it. This temp variable seems superfluous to me.
I simplified the code as follows:
- (void)viewDidLoad {
self.blueViewController = [[BlueViewController alloc]
initWithNibName:@"BlueView" bundle:nil];
[self.view insertSubview:blueViewController.view atIndex:0];
}
- (void)dealloc {
[blueViewController release];
[super dealloc];
}
My modified code ran just the same in the iPhone simulator.
Now, I know the rule that if you alloc something you need to release it. And I'm covering that in my dealloc
method. But is there some advantage to having a release directly in the ViewDidLoad
(the function where the alloc
was called)? Or is it equally ok to have a release
in your dealloc
method like this?
Thanks for any help,
-j
回答1:
Assuming blueViewController
is a retain
property, the temporary variable is not superfluous. Your simplification is creating a memory leak. This statement from the second snippet leaks:
self.blueViewController = [[BlueViewController alloc]
initWithNibName:@"BlueView" bundle:nil];
In terms of ownership, you own the object returned by alloc-init and then the property accessor claims ownership of the object again, resulting in the object being over-retained.
Using a temporary variable solves this problem. Another option is to use autorelease
:
self.blueViewController = [[[BlueViewController alloc]
initWithNibName:@"BlueView" bundle:nil] autorelease];
Note that after this statement you effectively own the object and you must release it in dealloc.
You did not mention how the property blueViewController
is declared. Anyway, whatever the semantics of the setter are (retain
, copy
, assign
), that statement is wrong. I already explained the most likely scenario: retain
. Let's have a look at the other two possibilites (without considering if they make sense at all):
If
blueViewController
happened to be acopy
property, the statement would leak too. The property accessor copies the original object and now the property holds a pointer to the copy and you lost track of the original object, immediately leaking it.The least likely scenario is that
blueViewController
is anassign
property because this is most likely wrong and you really wantretain
. But, anyway, theassign
properties are for objects you do not own, e.g. delegates, and you are not supposed to release them. You are assigning an object you own to it, so either you leak it or you incorrectly release the assign property.
回答2:
@property (retain) MyCLass *obj;
MyClass *tmpObj = [[MyClass alloc] init];
self.obj = tmpObj;
[tmpObj release];
In the first line you get ownership once via alloc
. Then in 2nd line you get ownership again as the property is retained. In 3rd line you release the ownership that you got via alloc
. Now you have a single ownership via retain property which you may release in future, may be in dealloc
.
Now consider what happens if you remove the tmpObj
.
self.obj = [[MyClass alloc] init];
In this line you get ownership twice, once via alloc
and once via property. Now [obj release]
once is not enough. You need to release it twice to avoid the leak, and naturally releasing twice is extremely bad and possible source to further memory leak. If you make another call to self.obj = anotherObj
then you are leaking the old one. To avoid this you need this temporary pointer.
回答3:
There's two reasons I can think of off the top of my head; the first, more specific to the example, is that you will often see similar methods where blueController
is allocated and initialized, then tested for validity before actually being assigned to self
's ivar. Following this pattern in every such method will make it easier for you to do tests in between creating the object and assigning it, should you realize that needs to happen. To my knowledge, if such an intermediary indeed remains superfluous, the compiler should optimize it out.
The second, more general purpose for this pattern within Cocoa is simply that Obj-C and Cocoa encourage extremely long, verbose names for methods and variables, so a single method call could end up spanning multiple lines; using method calls as direct arguments for other methods can quickly become unreadable, so conventions encourage setting up each argument for a method ahead of time, placing them in intermediary variables, then using the variables as arguments to enhance readability, and make it easier to change a single argument without having to dig around nested method calls.
来源:https://stackoverflow.com/questions/7042415/why-does-iphone-sample-code-use-so-many-intermediate-variables