为什么 iPhone 示例代码使用这么多中间变量?
我目前正在研究 Apress 的“Beginning iPhone 3 Development”。他们在示例应用程序中使用的标准类似于以下代码:
- (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(附加信息)
blueViewController 声明如下:
@property (retain, nonatomic) BlueViewController *blueViewController;
每当他们执行 alloc
时,他们都会将其放入某个临时变量(此处为 blueController
)中,然后分配它,然后释放它。这个临时变量对我来说似乎是多余的。
我将代码简化如下:
- (void)viewDidLoad {
self.blueViewController = [[BlueViewController alloc]
initWithNibName:@"BlueView" bundle:nil];
[self.view insertSubview:blueViewController.view atIndex:0];
}
- (void)dealloc {
[blueViewController release];
[super dealloc];
}
我修改后的代码在iPhone模拟器中运行得一样。 现在,我知道了这样的规则:如果你分配了一些东西,你就需要释放它。我在我的 dealloc
方法中介绍了这一点。但是直接在 ViewDidLoad(调用 alloc 的函数)中进行释放是否有一些优势?或者像这样在 dealloc
方法中使用 release
也同样可以吗?
感谢您的帮助,
-j
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
假设
blueViewController
是一个retain
属性,那么临时变量并不是多余的。您的简化会造成内存泄漏。第二个片段中的这条语句泄漏了:就所有权而言,您拥有 alloc-init 返回的对象,然后属性访问器再次声明该对象的所有权,导致该对象过度保留。
使用临时变量可以解决这个问题。另一种选择是使用 autorelease:
请注意,在此语句之后,您实际上拥有该对象,并且必须在 dealloc 中释放它。
您没有提到属性
blueViewController
是如何声明的。无论如何,无论 setter 的语义是什么(retain
、copy
、assign
),该语句都是错误的。我已经解释了最可能的情况:retain
。让我们看一下其他两种可能性(不考虑它们是否有意义):如果
blueViewController
碰巧是copy
属性,则该语句将会泄漏也。属性访问器复制原始对象,现在该属性保存了指向副本的指针,并且您失去了原始对象的踪迹,立即泄漏了它。最不可能的情况是
blueViewController
是一个assign
属性,因为这很可能是错误的,而您确实想要retain
。但是,无论如何,assign
属性适用于您不拥有的对象,例如委托,并且您不应该释放它们。您正在将您拥有的对象分配给它,因此要么泄漏它,要么错误地释放分配属性。Assuming
blueViewController
is aretain
property, the temporary variable is not superfluous. Your simplification is creating a memory leak. This statement from the second snippet leaks: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
: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.在第一行中,您通过
alloc
获得一次所有权。然后在第二行,您再次获得所有权,因为财产被保留。在第三行中,您释放通过alloc
获得的所有权。现在,您通过保留财产拥有单一所有权,您将来可能会释放该财产,可能在dealloc
中。现在考虑一下如果删除
tmpObj
会发生什么。在这一行中,您获得两次所有权,一次通过
alloc
一次通过 property。现在[obj release]
一次是不够的。您需要释放它两次才能避免泄漏,自然释放两次是非常糟糕的,并且可能会导致进一步的内存泄漏。如果您再次调用 self.obj = anotherObj ,那么您就会泄漏旧的。为了避免这种情况,你需要这个临时指针。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 viaalloc
. Now you have a single ownership via retain property which you may release in future, may be indealloc
.Now consider what happens if you remove the
tmpObj
.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 toself.obj = anotherObj
then you are leaking the old one. To avoid this you need this temporary pointer.我能立即想到两个原因:第一个,更具体的示例是,您经常会看到类似的方法,其中
blueController
被分配和初始化,然后在实际分配给self
之前测试有效性伊瓦尔。如果您意识到需要发生这种情况,那么在每个此类方法中遵循此模式将使您更容易在创建对象和分配对象之间进行测试。据我所知,如果这样的中介确实仍然是多余的,那么编译器应该将其优化掉。Cocoa 中此模式的第二个更通用的目的是 Obj-C 和 Cocoa 鼓励方法和变量使用极长、冗长的名称,因此单个方法调用最终可能会跨越多行;使用方法调用作为其他方法的直接参数很快就会变得不可读,因此约定鼓励提前为方法设置每个参数,将它们放置在中间变量中,然后使用变量作为参数以增强可读性,并使其更容易更改单个参数,而无需深入研究嵌套方法调用。
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 toself
'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.