Swift Digest
SE-0383 | Swift Evolution

Deprecate @UIApplicationMain and @NSApplicationMain

Proposal
SE-0383
Authors
Robert Widmann
Review Manager
John McCall
Status
Implemented (Swift 5.10)

01 何が問題だったのか

iOSアプリの @UIApplicationMain や macOSアプリの @NSApplicationMain は、アプリのエントリポイントを自動生成するためにUIKitやAppKitごとに用意された属性でした。これらは、UIApplicationDelegateNSApplicationDelegate に適合したクラスに付けておけば、コンパイラ側でプラットフォーム固有の main を合成してくれる、というものです。

しかし、SE-0281 で汎用の @main 属性が導入され、状況が変わりました。UIKit・AppKit は @main に完全対応しており、デリゲートプロトコルに適合するだけで main エントリポイントのデフォルト実装が提供されます。結果として、アプリ作者はエントリポイントの宣言方法として、

  • フレームワーク固有の @UIApplicationMain / @NSApplicationMain を使う
  • 汎用の @main を使う

という機能的に等価な2つの選択肢を前にすることになり、言語上の重複として冗長で紛らわしい状態になっていました。Xcode 14以降のテンプレートも既に @main を使っており、フレームワーク固有の属性を残し続ける意義は薄れていました。

02 どのように解決されるのか

@UIApplicationMain@NSApplicationMain を非推奨(deprecated)とし、@main への移行を促します。具体的には、Swift 5系の言語モードでは警告、Swift 6以降の言語モードではエラーとなります。警告と同時にfix-itが提供され、属性を @main に書き換えるだけで移行が完了します。

@UIApplicationMain // warning: '@UIApplicationMain' is deprecated in Swift 5
                   // fixit: Change `@UIApplicationMain` to `@main`
final class MyApplication: UIResponder, UIApplicationDelegate {
    /* ... */
}

fix-itを適用した結果は次のようになります。

@main
final class MyApplication: UIResponder, UIApplicationDelegate {
    /* ... */
}

UIApplicationDelegateNSApplicationDelegate には main エントリポイントのデフォルト実装があり、@main を付けたクラスがそれらのプロトコルに適合していれば、フレームワーク固有の属性を使ったときと実行時の挙動は同じになります。そのため、属性を書き換える以外のソース変更は不要です。

Swift 5系で段階的に切り替えたい場合は、upcoming feature flag DeprecateApplicationMain を有効にしておくことで、Swift 6を待たずに早めに診断を受けられます。

なお、@NSApplicationMain の挙動・移行手順は @UIApplicationMain とまったく同じです。