MacOSのシングルウィンドウアプリケーションを作るときにやっておくこと
ウィンドウを閉じたら、アプリも閉じるようにする
そうしないと審査で落ちます。
アプリ左上の赤丸の閉じるボタンやCommand+Wなんかでユーザーがウィンドウを閉じてしまったときにウィンドウはないけどアプリ自体は存在し続けるのが気に入らない模様です。
たしかに、何も手を打たないと、ウィンドウを閉じてもアプリケーションのメニューバーは残っています。
対応の選択肢としては、ウィンドウを復帰させる機能 を実装するか、 ウィンドウを閉じたら、アプリも閉じるようにする かの二択のようです。
私のケースではウィンドウを復帰させる機能を入れると追加でいろんなことを考えないといけなそうだと思い、ウィンドウを閉じたらアプリも閉じるようにする方針を採用しました。
対応方法
applicationShouldTerminateAfterLastWindowClosed
を使うことで対応可能です。
AppDelegate
のクラスに以下のように書いてあげれば、ウィンドウを閉じたときにアプリケーションも一緒に終了してくれます。
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
// シングルアプリケーションとしたいため、ウィンドウを閉じたらアプリケーションも閉じる仕様とする
return true
}
SwiftUIでAppDelegateとAppを共存させるには?
SwiftUIのエントリポイント(@mainを指定するコード)はAppDelegate
かApp
のどちらかをプロジェクト作成時の最初に選択することになります。
(あとからでもコードをいじれば変えることはできます)
で、上記の対応方法はAppDelegate
のクラスに書くのですがプロジェクトでApp
を選択している場合は、コードを書けないのかと思ってしまいます。
しかし、以下のようにApp
を継承したクラスの中で@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
を書いておくとAppDelegate
のコードに書いた内容が有効になります。
import SwiftUI
@main
struct NiceApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
// プロジェクトのコード
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// プロジェクトのコード
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
// シングルアプリケーションとしたいため、ウィンドウを閉じたらアプリケーションも閉じる仕様とする
return true
}
}
@NSApplicationDelegateAdaptor
を書くやり方は今回の話に限らず、AppDelegete
でないとできない方法が見つかったときの対応方法として覚えておくと結構いい感じだなと思いました。
そのうち、App
だけでなんでもできるようになっていくのかもしれませんが、それはまだ先になりそうです。
この件に関連して審査で何度かリジェクトをもらったので、知見を共有しました。
Discussion
大変貴重な知見をありがとうございます。
とありますが、実際のソースにはコードが記述されていないので修正お願いいたします。
Kyomeさん、こんにちは。
ご指摘ありがとうございます。修正しました。