SE-0383: Deprecated UIApplicationMain and NSApplicationMain
Introduction
@UIApplicationMain
と @NSApplicationMain
iOSとmacOSでそれぞれ、Appのsynthesized platform specific entory pointとして標準で使用されている。
それらの機能はSE-0281が出てから時代遅れのものとなっている。
SE-0281では、@main attributeが導入され、重複した機能として混乱を招いている。
この提案では、それらの時代をくれな代替方法を廃止することを目的としている。
Swift6からは@mainを使うようにし、UIApplicationMainなどを使用するとエラーとなる。
Motivation
UIKitとAppKitは @main atteributeによって全体的に包まれていて、"UIApplicationDelegate"や"NSApplicationDelegate" protocolに準拠するだけで、簡単にapplicationにすることができる。
これは、現状では、アプリの作者は entorypointとしての二つの選択肢が与えられていることを意味する。そして、二つ存在することは意味がない。
- ハードコードされたframeworkで特有のものを使う(@UIApplicationMain か @NSApplicationMain)
- どちらのframeworkでも使える@mainを使用する。
実行時には、"application delegate protocol"に準拠したクラスについた@main attributeの挙動は、framework特有のattribute(UIApplicationMain/NSApplicationMain)と全く同じである。
entrypointの概念を表現するための方法が二つ存在することは、紛らわしい。
この提案では、@mainに entrypointの表現方法を統一することを目的とする。
Proposed solution
pre-swift6モードでは、@UIApplicationMainとNSApplicationMainの使用はwarningになる。
warningでは、@mainで置き換えるように表示する。
Swift6では、それらの使用はerrorになる。
Detailed design
(UIApplicationMainとNSApplicationMainの使用方法は全く同じなので、このドキュメントではUIApplicationMainについてのみ議論する。NSApplicationMainにも全く同じことが適応できる。)
Framework特有のAttributeは アプリのentrypointを宣言することでボイラプレートなコードを自動化するために、言語に導入された。
UIKitでは、entrypointはUIApplicationMainを呼ぶことになる。
この呼び出しの最後のparameterはUIApplicationDelegateを継承したクラスの名前となる。
UIKitはそのdelegateクラスを探して 起動することで、application lifecycle callbackを起動する。
それゆえ、Swiftでは UIApplicationDelegate プロトコルの準拠したクラスにこのattributeをつける必要がある。
しかし、UIApplicationDelegateへの準拠は、lifecycle callbackのため以上のことをする。
'main' entrypointの標準の実装は片方の準拠のためであるが、UIApplicationMain attributeはそれを抑制する。
これは、framework 特有のattributeを使っている既存のユーザの移行にとって重要な点となる。
この提案では、コンパイラがUIApplicationMainの使用yをみつけると、それをmainで置き換えるように提案するwarningを出すようになる。
Swift6以降では、それはエラーとなる。
@UIApplicationMain // warning: '@UIApplicationMain' is deprecated in Swift 5
// fixit: Change `@UIApplicationMain` to `@main`
final class MyApplication: UIResponder, UIApplicationDelegate {
/**/
}
Fixitを実行すると、以下のようになる。
@main
final class MyApplication: UIResponder, UIApplicationDelegate {
/**/
}
この簡単な移行手順は、コンパイラにUIApplicationDelegateへの準拠されたmain entrypointを選択させる。
それ以外の変更は必要ない。
Source compatibility
既存の Libraryはビルドできるままである。なぜなら、それらはpre-Swift6モードだから。
それらでは、warningが出るだけである。
Swift6以降では、意図的に破壊的変更を引き起こし、古いattributeを使用しているとエラーとなる。
この破壊的変更は、主にapplication codeで起こる。なぜなら、ほとんどのlibraryやpackageは main entrypointを指定するframework specific attributeを使用してないからである。
新しいコードでは、templateはすでにmainを使うように変更されている。(Xcode14 or later)
UIApplicationMainをmainに変更するだけなので、簡単。
一箇所の変更のみに見える。