短いバージョン:
release
Cocoa アプリケーションの終了時 に NSView オブジェクトのサブビューにメッセージが送信されないのはなぜですか?- この動作をオーバーライドする方法はありますか?
例:
以下MyView
に示すクラスNSView
は、作成および破棄されたときにコンソールに報告するサブクラスにすぎません。私はそれをテストし、それが適切に機能することを発見しました。ただし、アプリケーション デリゲートの次のコード スニペットに示すように使用すると、予期しない結果が表示されます (サンプル出力を参照)。
// MyView:
@interface MyView : NSView { }
@end
@implementation MyView
- (id)initWithFrame:(NSRect)frameRect
{
if ((self = [super initWithFrame:frameRect]) == nil) { return nil; }
NSLog(@"init %@", self);
return self;
}
- (void)dealloc
{
NSLog(@"dealloc %@", self);
[super dealloc];
}
@end
// Application delegate:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(@"begin");
parentView = [[MyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
MyView * myView = [[MyView alloc] initWithFrame:NSMakeRect(10, 10, 80, 80)];
[parentView addSubview:myView];
[myView release];
NSLog(@"run");
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
NSLog(@"quit");
[parentView release];
NSLog(@"end.");
}
このアプリケーションは、次の出力を生成します。
開始
init<
MyView: 0x10013f840>
init<
MyView: 0x10261b620>
run
quit
dealloc<
MyView: 0x10013f840>
end.
問題:
アプリケーションの終了時に最初のビュー オブジェクトが解放されていることがはっきりとわかります。また、NSView
オブジェクト自体が解放されると、オブジェクトがサブビューを自動的に解放する (テストおよび検証済み) ことを確信しています。ただし、アプリケーションの終了時に、これらのサブビューが解放されていないようです。
長いバージョン: (別名、なぜ一体誰が気にするのでしょうか? :)
まず、実行中のアプリケーションが終了したときにメモリが解放される方法に精通していると言っておきましょう。メッセージが送信されなくても、サブビューが適切に破棄されることはわかっているrelease
ので、これがリークであるとは心配していません。実際、私の質問 #1 に対する答えは、「アプリケーションが終了しようとしているときにサブビューを解放する必要がないため」であると確信しています (ただし 100% 確実ではありません)。
アプリケーションがデバッグ モードで実行されている間、単純な手巻きのコードを使用してメモリ トラッキングを行います。すべてのカスタム クラスの and メソッドで and メソッドを呼び出し、この関数を使用してTrace_Init()
、アプリケーションTrace_Dealloc()
のCocoa部分が終了した後に未リリースのオブジェクトを報告します。これは、Apple のメモリ リーク パフォーマンス ツールを定期的に実行するよりもはるかに簡単だと思います。実行中にメモリ リークが発生した場合は、アプリケーションが終了するとすぐにわかります。init
dealloc
atexit()
ただし、dealloc
終了時に呼び出しがないということはNSView
、サブビューとして使用されているカスタム サブクラスのいずれかが、アプリケーションを終了したときにメモリ リークとして表示されることを意味します。したがって、私の質問#2の理由。終了時に Cocoa がすべてを解放して、メモリ追跡が適切に終了できるようにしたいと考えています。当然、デバッグ モードでのデフォルトの動作のみをオーバーライドします。私のリリースしたアプリでは、メモリ追跡コードが有効になっておらず、通常どおり効率的に終了できるはずです。
それでおしまい!(ふぅ) ここまで読んでくれてありがとう。