为啥我必须最后调用 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,而不是先调用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥react的组件要super

子类要调用父类的方法,必须使用super关键字。这句话对吗,为啥?

super this 为啥不能同时存在

为啥我不能在 super 上调用 Core Data Accessors?

为啥我不能在 Swift 中调用 UIViewController 上的默认 super.init()?

为啥关闭 translatesAutoResizingMasks 会导致自动布局崩溃,抱怨我需要调用 [super layoutSubviews]?