ウィンドウクローズ時にアプリも終了させるには

ドキュメントベースでないCocoa Applicationの場合、ウィンドウが1つしか存在しない訳ですが、タイトルバー上のクローズボタンでウィンドウをクローズしてもアプリケーションが終了しないのをうっとうしいと思われる方も多いのではないでしょうか。閉じてしまったらウィンドウをもう一度開ける訳でもないですし、後はアプリケーションを終了するしかないのですから...

そこでウィンドウクローズ時に自動的にアプリも終了させる方法について調べてみました。
方式の概略は以下のとおりです。

自前のコントローラオブジェクトをウィンドウオブジェクトのdelegateとして登録する
自前のコントローラのクラスにウィンドウオブジェクトがウィンドウクローズ時にdelegateに対して呼び出すメソッドを実装する
上記メソッド内でアプリケーションオブジェクトの終了要求メソッドを呼び出す

ウィンドウオブジェクトがクローズ時にdelegateに対して呼び出すメソッドには以下の2つがあります。(NSWindow参照)


- (BOOL)windowShouldClose:(id)sender

- (void)windowWillClose:(NSNotification *)aNotification

両者の違いは、前者はウィンドウを本当にクローズしてよいか確認するために呼び出されるもので(復帰値でNOを返すとウィンドウはクローズされない)、後者はウィンドウがクローズされることを通知するものです。
実験してみたところ、Cocoa Applicationではタイトルバーのクローズボックスでウィンドウをクローズすると

 windowShouldClose: → windowWillClose:

の順で呼び出され、メニューからアプリケーションを終了すると「windowWillClose:」のみが呼び出されました。

どちらでもよさそうなものですが、今回の要件としては、クローズボックスでウィンドウをクローズしたときにアプリケーションを終了させたいので「windowShouldClose:」をインプリメントします。

注) 実験的に「windowWillClose:」をインプリメントしてその中でアプリの終了要求を行ってみましたが、その場合はメニューから終了要求時に呼ばれた後、メソッド内から呼び出したアプリの終了要求に対して再度このメソッドが呼ばれてしまうという副作用があることがわかりました。

サンプルプログラムの作成手順を以下に示します。(プロジェクトの作成手順の説明は省略します)

【作成環境】

Mac OS X v10.3.3
Xcode v1.2

1.自前のコントローラクラスの作成

Interface Builderのnibパレットの「Classes」タブのペイン上でNSObjectのサブクラスとしてUCAppControllerという名前のクラスを作成します。
今回はOutletやActionの設定は行わないのでこのままソースファイルの作成も行います。

2.自前のコントローラクラスのインスタンス化

「Classes」タグのペイン上で先ほど作成したUCAppControllerクラスをインスタンス化します。

3.ウィンドウオブジェクトのDelegateとして自前のコントローラを登録

nibパネル上でコントロールキ+マウスドラッグでウィンドウからコントローラのインスタンスに接続し、infoパネルでdelegateとして接続します。

4.ウィンドウクローズ時のデリゲートメソッドのインプリメント

コントローラクラス(UCAppController)のインターフェースファイルとインプリメントファイルに以下のコードを追加します。

UCAppController.h : 自前コントローラクラスインターフェースファイル
// ウィンドウクローズ確認
- (BOOL)windowShouldClose:(id)sender;

UCAppController.m : 自前コントローラクラスインプリメント ファイル
// ウィンドウクローズ確認
- (BOOL)windowShouldClose:(id)sender
{
    // ウィンドウクローズでアプリケーションも終了
    [NSApp terminate:self];
    return YES;
}

インプリメントファイル内の

 [NSApp terminate:self];

の行がアプリケーションに終了要求を送っている箇所で、ターゲットのNSAppというのはアプリケーション内にただ1つ存在するNSApplicationクラスのインスタンスオブジェクトを示します。

以上で作業は完了ですのでビルドして走らせてみてください。

■もう一つの解■

NSWindowクラスのdelegateではなく、NSApplicationクラスのdelegateとして実装する方法もあります。具体的には以下のdelegateメソッドを実装し、固定値YESを返すようにします。

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication

沼田さんの「Cocoa に関するヌマタメモ」を参考にさせていただきました。Thank you!!

サンプルプログラムダウンロード(1.4MB)


一覧へ戻る