我一整天都在阅读有关为什么在viewDidUnload中将视图设置为nil并在dealloc中发布的原因。所有文章都在重复同样的事情。是的,我知道幕后指示是不同的,但实际的区别是什么?
var = nil
[var release]
对我来说,回收内存的两种方式都有相同的最终结果。那么为什么一个在另一个呢?每本书都告诉我在viewDidUnload
中设置为nil并在dealloc
中发布。如果视图在viewDidUnload
中发布并在dealloc
中填充,则应该指出可能发生的不良事件。
·H
#import <UIKit/UIKit.h>
@interface DisclosureDetailController : UIViewController {
UILabel* label;
}
@property (nonatomic, retain) IBOutlet UILabel* label;
@end
的.m
#import "DisclosureDetailController.h"
@implementation DisclosureDetailController
@synthesize label;
- (void)viewDidUnload {
self.label = nil;
// OR [self.label release];
[super viewDidUnload];
}
- (void)dealloc {
[self.label release];
// OR self.label = nil;
}
答案 0 :(得分:25)
首先,行
[self.label release];
无论你在哪里打电话,都是绝对错误的。您应该从不调用-release
关于属性访问的结果。这与编写[[self label] release]
完全相同,我希望你能认识到这是错误的。
您的代码示例应如下所示:
- (void)viewDidUnload {
self.label = nil;
[super viewDidUnload];
}
- (void)dealloc {
[label release];
[super dealloc];
}
如果我们先看-viewDidUnload
,那就很简单了。 self.label = nil;
是正确的。同样正确的是[self setLabel:nil];
。虽然不太好,但写[label release], label = nil;
也是可以接受的。最后一种形式不是很好,因为它绕过了setter方法,这可能比简单地释放属性做更多的事情(例如,它可能保持关注属性值的内部状态)。它还绕过了KVO通知。
这里真正的问题是你在-dealloc
中做了什么。很多人都认为说self.label = nil;
是完全没问题的,实际上,大多数时候这都会有效。问题是,其余的时间会导致细微的错误。调用setter有两件事可以做。首先,如果手动实现setter方法,它可能会导致类中的副作用(即使您没有自己实现setter,也可能是子类)。第二是它可以播放KVO通知。当你在-dealloc
时,这两件事都不合适。通过直接释放ivar,如[label release];
,您可以避免潜在的副作用和KVO通知。
答案 1 :(得分:4)
实际差异如下。
使用属性访问器将属性设置为nil将使合成方法在释放现有属性后保留新的nil属性。
// we will take for granted that you synthesize this property
@property (nonatomic, retain) IBOutlet UILabel* label;
我们将使用属性访问器并将其设置为nil。
//This will in actuality set the new value of nil to the label variable after
//releasing the existing label that it had a retain count on.
self.label = nil;
接下来我们将直接发布
//This line on the other hand will merely release the label directly.
//As soon as the label is deallocated you will have a handle to an invalid object.
//(memory space that used to be your label)
[label release];
现在我们将展示属性访问器的简化版本。 (不要用字面意思)
//Simply put the following is an pseudo equivalent of the property setter.
[label release]
label = nil;
这里的要点是属性访问器处理释放它保留的标签。并将其设置为您提供的任何东西(在这种情况下为零)
因此添加以下代码
label = nil;
不释放保留的对象会导致内存泄漏,并且您将在不再有指针的标签上有保留计数。
注意强>:
另一件需要考虑的事情。 任何指针都是零。将能够 接受消息。作为回报他们 将以零回复。一个对象 另一方面被释放了 一旦该内存被释放 你的信息很有可能发生 抛出一个错误。结果是 不可预知的。这是一个很好的理由 用于将属性设置为nil。 它不仅会处理发布 对于它持有的对象。但 它也会给你一个对象 可以安全地发送消息而不吹 起来。
好点@WaltSellers
访问变量 - 无论是属性访问者还是实例变量。 - 完全释放后。将导致“未定义”操作。这意味着访问可能会正常运行,或者它可能会破坏应用程序的其他部分,或者它可能会快速爆炸并终止违规应用程序。基本上在释放后将变量设置为nil将使您能够超越该错误。
与我分开的提示
克服属性访问器和实例变量的误解我只是@synthesize并告诉它设置一个变量名。
@synthesize label = _label;
这样做可以让我将self.label与其实例变量区分开来。如果没有前面的_
,你就不能直接访问label变量了