【问题标题】: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]。为什么?

【问题讨论】:

    标签: iphone cocoa-touch memory-management uikit


    【解决方案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。
          猜你喜欢
          • 2011-09-29
          • 1970-01-01
          • 2014-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多