为啥我必须最后调用 super -dealloc,而不是先调用?
Posted
技术标签:
【中文标题】为啥我必须最后调用 super -dealloc,而不是先调用?【英文标题】:Why do I have to call super -dealloc last, and not first?为什么我必须最后调用 super -dealloc,而不是先调用? 【发布时间】:2010-10-28 22:24:33 【问题描述】:正确的例子:
- (void)dealloc
[viewController release];
[window release];
[super dealloc];
错误的例子:
- (void)dealloc
[super dealloc];
[viewController release];
[window release];
Although 在几乎所有其他情况下,当覆盖一个方法时,我会首先调用 super 的方法实现,在这种情况下,Apple 总是在最后调用 [super dealloc]。为什么?
【问题讨论】:
【参考方案1】:这只是一个指导方针。在[super dealloc]
之后可以调用其他指令。但是您不能再访问超类的变量,因为它们在您调用[super dealloc]
时被释放。在最后一行调用超类总是安全的。
如果 KVO 和依赖(触发)键依赖于已发布的成员变量,它们也会产生副作用。
【讨论】:
使用 ARC,您根本不必调用[super dealloc]
,这样做时会产生编译器错误。【参考方案2】:
[到最后一篇] 引用委托的tableView难道不负责释放它自己的委托吗?我认为它在设置时会保留它(因此您可以释放或自动释放它)并且它会自行处理?
至于 OP 问题,如果我在构造,我总是先调用 super,如果我在破坏,我会最后调用 super。我认为它是“我想要超级构建它想要的东西,这样我就可以在此基础上进行构建,并且我希望超级在我自己清理之后最后拆除。”几乎我使用的所有调用都在构造,但 dealloc 除外,所以这就是为什么你总是会在我的 dealloc 代码中看到它。
【讨论】:
【参考方案3】:这里是实际示例,其中 [super dealloc] 必须放在最后,否则对 removeFromRunLoop 的调用将导致崩溃。我不确定 NSOutputStream 的 removeFromRunLoop 内部发生了什么,但在这种情况下它似乎访问了“self”。
设置:
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
处理:
- (void)dealloc
if (outputStream)
[outputStream close];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream release];
outputStream = nil;
delegate = nil;
[super dealloc]; // must be last!
【讨论】:
【参考方案4】:您实际上几乎在末尾有[super dealloc]
,因为它释放了超类的变量并且它们不能再被访问。
一个例外是,如果您有一个 UITableViewController 的子类使用另一个类作为其表视图委托。在这种情况下,您必须在[super dealloc]
之后释放表视图委托,因为表视图正在引用表视图委托,并且必须先释放表视图。
【讨论】:
您能否详细说明您的异常情况?对我来说这听起来有点不对。 @Mark:我也听错了。通常,您甚至不会首先保留委托以避免保留周期。【参考方案5】:[super dealloc] 正在释放对象使用的内存,包括指向 viewController 和 window 的指针。在释放变量后引用它们充其量是危险的。
见this answer。
【讨论】:
【参考方案6】:我对 iPhone 编程一无所知,但我认为出于同样的原因,需要以相反的顺序调用析构函数。您要确保在调用超类之前清理所有“垃圾”。如果你反其道而行之,事情就会变得一团糟。例如,如果你的析构函数需要访问超级析构函数已经释放的内存:
class X
private Map foo;
function __construct()
foo = new Map();
function __destruct()
foo.free;
class Y extends X
function __construct()
super.__construct();
map.put("foo", 42);
function __destruct()
super.__destruct();
if (map.containsKey("foo")) // boooooooooom!
doSomething();
您可能不会在您的代码中遇到此问题,因为“您知道自己在做什么”,但不做此类事情是一种更安全且整体更好的做法。
【讨论】:
我的猜测是因为它回答了这个问题,至少部分回答了这个问题。另一方面,投反对票通常意味着答案没有帮助或完全错误。如果是错的,我很想知道为什么,这样我就可以从我的错误中吸取教训。还是你只是在争论? 我没有投反对票;这是一个很好的答案。然而,downvote 是公平的,因为它是一个猜测,而不是特定于 Cocoa 框架。 @n3rd,我同意@adam,这不是关于 cocoa/obj-c 的具体答案 如果问题确实像我假设的那样具有一般性质,那是完全无关的。如果您想知道为什么对“空对象”进行方法调用是个坏主意,那么无论您是在谈论 Java、php、C++ 还是 javascript。以上是关于为啥我必须最后调用 super -dealloc,而不是先调用?的主要内容,如果未能解决你的问题,请参考以下文章
子类要调用父类的方法,必须使用super关键字。这句话对吗,为啥?
为啥我不能在 super 上调用 Core Data Accessors?
为啥我不能在 Swift 中调用 UIViewController 上的默认 super.init()?
为啥关闭 translatesAutoResizingMasks 会导致自动布局崩溃,抱怨我需要调用 [super layoutSubviews]?