2009-05-26 4 views
29

正しい例:alsmost他のすべてのケースでsuper-deallocを最後に呼び出さなければならないのはなぜですか?

- (void)dealloc { 
    [super dealloc]; 
    [viewController release]; 
    [window release]; 
} 

Althoug私は最初のスーパーのメソッドの実装を呼ぶようなメソッドをオーバーライドする場合、このケースでは、Appleは常に[スーパーのdeallocを呼び出します。

- (void)dealloc { 
    [viewController release]; 
    [window release]; 
    [super dealloc]; 
} 

間違った例] 最終的には。どうして?

答えて

54

ちょうどその指針です。 [super dealloc]の後に他の手順を呼び出すことができます。ただし、[super dealloc]を呼び出すと解放されるため、スーパークラスの変数にはアクセスできなくなります。最後の行でスーパークラスを呼び出すことは常に安全です。

また、すでにリリースされているメンバ変数に依存する場合、KVOおよび依存(トリガ)キーは副作用を引き起こす可能性があります。

+5

ARCでは、 '[super dealloc]'をまったく呼び出す必要はありません。するとコンパイルエラーが発生します。 – teradyl

12

私は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(); 
     } 
    } 
} 

あなたは「あなたは何をやっている知っている」ので、あなたコードでこの問題が発生したが、それではないことそのようなことをしないで安全で全体的に優れた習慣です。

+1

なぜこれが落とされたのか、誰でも気にしていますか? – n3rd

+4

なぜこれがupvotedされたかを精緻化するために気に? –

+0

私の推測は、少なくとも部分的に質問に答えたからです。一方、下降法は、一般的に、その答えが役に立たなかったか、または間違っていることを意味します。もしそれが間違っていたら、どうして私のミスから学ぶことができるのかを知りたいです。それともあなたは議論になっていたのですか? – n3rd

5

[super dealloc]は、オブジェクトによって使用されるメモリ(viewControllerおよびwindowへのポインタを含む)を解放しています。あなたがそれらを解放した後に変数を参照するのは、せいぜい危険です。

this answerを参照してください。

1

実際には、スーパークラスの変数を解放してアクセスできなくなるため、ほぼ[super dealloc]になります。

例外は、別のクラスをテーブルビューデリゲートとして使用しているUITableViewControllerのサブクラスがある場合です。その場合、[super dealloc]の後にテーブルビューデリゲートを解放する必要があります。これは、テーブルビューがテーブルビューデリゲートを参照しており、テーブルビューを最初に解放する必要があるためです。

+1

例外についてもう少し詳細を教えてもらえますか?それは私には少し間違って聞こえる。 –

+1

@マーク:私にも間違って聞こえる。通常、保持サイクルを避けるために、最初にデリゲートを保持することさえありません。 –

2

[super dealloc]が最後でなければならない実際の例です。それ以外の場合は、removeFromRunLoopの呼び出しによってクラッシュが発生します。私はNSOutputStreamのremoveFromRunLoopの内部で何が起こるのか分かりませんが、この場合は 'self'にアクセスするようです。

セットアップ:

[outputStream setDelegate:self]; 
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

DEALLOC:[最後のポストへ]

- (void)dealloc { 
    if (outputStream) { 
     [outputStream close]; 
     [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] 
           forMode:NSDefaultRunLoopMode]; 
     [outputStream release]; 
     outputStream = nil; 
    } 
    delegate = nil; 
    [super dealloc]; // must be last! 
} 
1

はのtableViewデリゲートは、それ自身のデリゲートを解放する責任を参照しませんか?私はそれが設定されたときにそれを保持していると思うだろう(あなたがそれをリリースするか、または自動リリースすることができるように)、それはそれ自身を世話するだろうか?

OPの質問については、私が建設しているならば、私はいつもスーパーをまず呼び出すでしょう。「自分が望むものをスーパービルドして、それを上手にしたいと思っています。私が自分で掃除した後、スーパーが最後に壊れるようにしたいと思っています。私が使用する事実上すべての呼び出しは、deallocを除いて構築されています。だから、それはいつも私のdeallocコードで最後に見えるでしょう。