2009-09-07 12 views
12

私は見た後にさらに明確化を求めていますWhat is responsible for releasing NSWindowController objects?誰がNSWindowControllerを所有していますか?

私は甥のための簡単な在庫管理アプリケーションを書いています。私は、 "ライブラリ"の内容を表示するテーブルビューを持っています。新しいアイテムをライブラリに追加するには、 '+'ボタンをクリックします。このボタンは、項目の詳細を促す新しいウィンドウを開き、「OK」をクリックすると入力を検証します。

すべてはうまくいきます。しかし、私はメモリ管理についての質問があります。他に何もeditorControllerを参照していないので、私は、addNewItem:の終わりにリリース(も自動解放)editorControllerすることはできません

- (IBAction)addNewItem:(id)sender { 
    LibraryItemEditorController *editorController = 
    [[LibraryItemEditorController alloc] 
      initWithWindowNibName:@"LibraryItemEditor"]; 

    [editorController showWindow:nil]; 
    // editorController is "leaked" here, it seems. 
} 

;:新しいウィンドウを作成するために、私は次のコードを使用しますもし私がそれをリリースすると、ウィンドウはすぐに消えます。しかし、ウィンドウが閉じられるとウィンドウコントローラーが解放されるようにします。 AppleのWindow Programming Guideでは、私は次をお読みください。

あなたは に窓の開閉が、それは 文書の一部でない場合、両方のウィンドウとウィンドウコントローラ が離れて行く NSWindowControllerのサブクラスを作りたい場合 として、ウィンドウのデリゲートを NSWindowWillCloseNotificationを観察したりすることができ、 windowWillClose:メソッドを実装し、あなたの 実装でコードの 次の行を含める:

[self autorelease]; 

私は、ウィンドウコントローラのwindowWillClose:メソッドで[self autorelease]を使用しました。これは動作し、メモリをリークしません。しかし、それはちょうど醜い感じです。 addNewItem:はメモリがリークしているように見えますが、静的解析でもそう考えています。 私はが実際にはwindowDidClose:の世話をしていることを知っていますが、それは間違っていると感じます。さらに、ウィンドウコントローラは今までそれ自体を保持することなくそれ自体を解放している。これはすべて、私が学んだメモリ管理ルールに反するものです。

私の他のオプションは、親コントローラ上IVARを置く(NSWindowControllerまたはNSWindowController秒のNSMutableSetのいずれか)と、親コントローラにNSWindowWillCloseNotificationを監視し、それに応答して、それを解放することです。これはよりクリーンで、おそらく私がやることです。それはまた、かなりの量の仕事ですが、私の質問につながります。

NSWindowDidCloseNotificationこれを行う標準的な方法を見ていますか?オンデマンドで作成および破棄される標準的な方法はNSWindowControllersですか? [self autorelease]は伝統的に推奨されているオプションですか?これが問題になるという静的分析が行われたのは今のところですか?

答えて

5

あなたのウィンドウがモーダルであるようですが、その場合には、聞こえる:

[NSApp runModalForWindow:[editorController window]]; 
[editorController release]; 

ここで非モーダルウィンドウに1つのパターンがあります:

@implementation QLPrefWindowController 

+ (id) sharedInstance 
{ 
    if (!_sharedInstance) 
    { 
     _sharedInstance = [[QLPrefWindowController alloc] init]; 
    } 
    return _sharedInstance; 
} 

- (void)windowWillClose:(NSNotification *)notification 
{ 
    if ([notification object] == [self window] && self == _sharedInstance) 
    { 
     _sharedInstance = nil; 
     [self release]; 
    } 
} 

そして、窓の缶にアクセスしたり、表示したい人+sharedInstanceクラスメソッドを使用してください。ウィンドウが既に表示されていない場合は作成され、そうでない場合は現在表示されているウィンドウが表示されます。

+0

私はモーダルウィンドウとして実行していませんでしたが、おそらく私はそうすべきだと思います。共有インスタンスのバージョンはインスペクタパネルには意味があると思います。同時に、複数のウィンドウを同時に開く必要がある場合は、それらを直接把持することはおそらく意味があります。これは私のために働く。 –

+0

クラスのメソッドはインスタンス変数にアクセスできないため、この答えは正しいとは思いません。この場合、クラスメソッド "sharedInstance"が "_sharedInstance"というiVarにアクセスしようとしています。これは毎回失敗します。 – Bryan

+0

'_sharedInstance'は静的変数であり、ivarではありません。それは一般に共有インスタンスがどのように実装されるかです。 –

0

クラスメソッドがiVarsにアクセスできないため、上記の非モーダル状況の解決策は正しくありません。上記の方法は、1の保持カウントをLPWindowControllerのインスタンスを返します

+ (id) autoreleasingInstanceShowingWindow 
{ 
    LPWindowController *obj = [[LPWindowController alloc] initWithWindowNibName:@"myWindow"]; 
    [obj showWindow:[NSApp delegate]]; 

    return obj; 
} 

また、コントローラの画面を示しています。私はこのようになります(LPWindowControllerと呼ばれる私のNSWindowControllerサブクラスの)クラスメソッドを作成することによって、この問題を解決しました。そうでないと、呼び出し側が "showWindow:"を呼び出してLPWindowControllerのウィンドウを表示させなければならないので、これは重要です。呼び出し元がこれを行うことに失敗した場合(これはバグかもしれません)、コントローラは決して解放されません。コントローラーの割り当て/初期化時にウィンドウを強制的に表示することで、この落とし穴を回避します。

次に、IBに我々はLPWindowControllerクラスに私たちのウィンドウのデリゲートを設定し、そのクラスでこれを追加します。

- (void) windowWillClose:(NSNotification *)notification 
{ 
    [self autorelease]; 
} 

そして、我々は我々のウィンドウを作成し、表示するために必要がある場合、最終的に、我々は単純に以下のメソッドを使用しますLPWindowControllerで "alloc/initWithWindowNibName:"を呼び出す代わりに、

LPWindowController *cont = [LPWindowController autoreleasingInstanceShowingWindow]; 
cont = nil; 

2行目が重要です。まず、 "未使用変数cont"に関する警告を削除します。第2に、ぶら下がったポインタの危険性を排除します。 LPWindowControllerのインスタンスが一旦解放されると、contが明示されていなければ、ガベージメモリを指し示します。

とにかく、この問題に対する私の推奨されたアプローチです。

関連する問題