この記事の要点
- Swift 5.3 が正式リリースされました。言語の洗練、開発体験の向上、そして Swift を書ける場面を広げるためのエコシステム拡張に重点を置いたリリースです。
- 言語・標準ライブラリには、
@mainによるプログラムエントリポイント、複数の trailing closure、enumへのComparable適合の自動合成、Float16、@escapingクロージャでの暗黙的selfの利用範囲拡大など、多くの洗練が加わりました。 - ランタイムでは、バイナリのコードサイズと実行時メモリ使用量が大きく改善されました。型を多く宣言するプロジェクト(SwiftUI アプリなど)で特に効果が大きく、Swift で書いたアプリの heap メモリ使用量が同等の Objective-C プログラムより少なくなりうるとされています。
- 開発体験では、コード補完が最大 15 倍高速化し、インクリメンタルビルドの高速化、診断(エラーメッセージ)の改善、デバッグの改善が入りました。
- エコシステムでは、Swift Package Manager がリソース・ローカライズ・バイナリ依存(XCFramework)・条件付きターゲット依存をサポートしました。
- Apple プラットフォーム向けには Xcode 12 に同梱され、Linux ツールチェインや Docker イメージも提供されます。Windows 向けの公式ツールチェインも数週間以内に提供予定とされました。
主な変更点
言語・標準ライブラリの更新
Swift 5.3 では、Swift Evolution プロセスを経た次の Proposal が実装されました。ボイラープレートや冗長なコードを減らし、より多くの機能をライブラリ側で定義できるようにする洗練が中心です。
-
@main: 型ベースのプログラムエントリポイント(SE-0281): 型に@mainを付けることで、その型のstatic func main()をプログラムの起点にできます。main.swiftを用意する代わりに、エントリポイントをライブラリやフレームワーク側で定義できます。@main struct MyApp { static func main() { print("Hello, Swift 5.3!") } } -
複数の trailing closure(SE-0279): 引数に複数のクロージャを取る関数を、いずれも trailing closure として渡せるようになりました。2 つ目以降はラベル付きで書きます。
UIView.animate(withDuration: 0.3) { self.view.alpha = 0 } completion: { _ in self.view.removeFromSuperview() }あわせて、trailing closure の引数へのマッチング方式が forward-scan(前方走査)に変更されました(SE-0286)。
-
enumへのComparable適合の自動合成(SE-0266): ケースの宣言順に基づくComparable適合をコンパイラが自動合成できるようになりました。enum Size: Comparable { case small, medium, large } Size.small < Size.large // true -
Float16(SE-0277): 半精度浮動小数点数型Float16が標準ライブラリに追加されました。 -
@escapingクロージャでの暗黙的selfの利用範囲拡大(SE-0269): 参照循環が起こりにくい状況では、@escapingクロージャ内でもself.を省略できるようになりました(例:selfを明示的にキャプチャ済みの場合)。 -
didSetセマンティクスの洗練(SE-0268):didSetが古い値を参照しない場合、不要な getter 呼び出しを省くようになりました。 -
複数パターンの
catch句(SE-0276): 1 つのcatch句に複数のパターンをカンマ区切りで書けるようになりました。do { try perform() } catch Error.invalid, Error.expired { handle() } -
enumのケースをプロトコル要件(witness)として使う(SE-0280): 引数のないcaseや、関連値を持つcaseを、プロトコルの static プロパティ要件や static 関数要件の実装として使えるようになりました。 -
コンテキスト依存のジェネリック宣言での
where句(SE-0267): ジェネリックなコンテキスト内の宣言に対してもwhere句で制約を書けるようになりました。 -
未初期化ストレージにアクセスできる
Stringイニシャライザ(SE-0263): 未初期化のバッファに直接書き込んでStringを初期化できるイニシャライザが追加され、文字列構築を効率よく書けます。 -
簡潔な magic file 文字列への移行緩和(SE-0285):
#fileの表現をモジュール名とファイル名による簡潔な形式へ移行する際の互換性に配慮した変更です。 -
Swift のメモリ整合性モデルの明確化(SE-0282): 並行処理におけるメモリアクセスの順序保証(メモリモデル)が文書として明確化されました。これは将来のアトミック操作 API の基盤となります。
このほか、よく報告されていたコンパイラの制限もいくつか修正されました。プロトコル要件への未適用参照(unapplied reference)のサポート、lazy プロパティでの didSet / willSet の定義、関連型を持つプロトコルに適合するジェネリッククラスでのデフォルト実装の利用などです。
ランタイム性能の改善
Swift 5.3 は、バイナリのコードサイズと実行時メモリ使用量を大きく改善しました。
- iOS に同梱される UIKit アプリ(元は Objective-C)を Swift で書き直したものの計測では、コードサイズが Objective-C 版の約 2.3 倍(Swift 4 時点)から 1.5 倍未満(Swift 5.3)まで縮みました。
- オープンソースの SwiftUI アプリ MovieSwiftUI では、アプリケーションロジックのコードサイズが Swift 5.1 比で 40% 以上削減されました。
- 400 個のモデルオブジェクトの配列を作るテストアプリでは、ランタイムオーバーヘッドによる heap メモリが Swift 5.1 の 1/3 未満になりました。
コードサイズの改善は、コンパイラが値型の生成・コピー・破棄のために生成する「value functions」の縮小によるもので、型を多く宣言するプロジェクト(特に SwiftUI アプリ)で効果が大きくなります。またランタイムの改善によりプロトコル適合などの起動時キャッシュが減り、Swift で書いたアプリの heap メモリ使用量が同等の Objective-C プログラムより少なくなりうるとされています。
開発体験の改善
- コード補完: 関数本体内での補完の繰り返し呼び出しが、同一ファイル内の以前の計算を再利用することで Swift 5.2 比で最大 15 倍高速になりました。この高速化は Xcode と SourceKit-LSP の両方で効きます。また、ユーザー定義型の callable な値(SE-0253)も補完でサポートされました。
- インクリメンタルビルド: ソースファイル間で重複していたコンパイラの作業を避け、変更されていないコードをより正確に識別することで、インクリメンタルビルドが高速化しました。宣言の順序やネストに対する挙動の不安定さも修正されています。
- 編集中のインデント: SourceKit の自動インデント実装が刷新され、約 50 件のフィードバックが修正されました。クロージャを含むメソッドチェーン、複数行にまたがる引数やコレクション要素、複数行の
if/guard/while条件などのインデントが改善されています。 - コンパイラ診断: Swift 5.2 の診断改善をさらに進め、特に SwiftUI コードでのエラーメッセージの品質と精度が向上しました。Swift 5.3 で新しい診断アーキテクチャへの移行が完了しています。たとえば、ジェネリック引数の要件(適合の不足など)が満たされない場合に、従来は「ambiguous without more context」という分かりにくいエラーが出ていましたが、Swift 5.3 では不足している適合と、その要件の出どころを示す note が表示されるようになりました。
- デバッグ: ランタイム失敗時のエラーメッセージが改善され、デバッグ情報があれば標準ライブラリの trap の理由が表示されるようになりました。また LLDB が、別マシンでコンパイルされたバイナリのデバッグでもより頑健になり、ビルドマシンの SDK パスの自動認識・再マッピングなどが行われます。
Swift Package Manager の更新
- リソース(SE-0271): 画像やデータファイルなど、実行時に必要なリソースをパッケージに含められるようになりました。リソースはターゲット単位でスコープされ、ビルド時に処理・埋め込みが行われ、Foundation の
BundleAPI から参照できます。 - ローカライズ(SE-0278):
.stringsファイルやリソースのローカライズ版など、ローカライズ可能なコンテンツをパッケージに含められるようになりました。.lprojディレクトリで追加し、Foundation API から参照します。 - バイナリ依存(SE-0272): XCFramework として配布されるビルド済みライブラリをパッケージから提供できるようになりました。ソースコードとして配布できないライブラリへの依存が可能になります(現時点では Apple プラットフォーム向けビルドのみ)。
- 条件付きターゲット依存(SE-0273): ターゲットの依存をプラットフォームごとに限定するなど、条件付きで宣言できるようになりました。なお、ビルド構成に基づく条件は Proposal には含まれていたものの未実装で、Swift 5.3 には入っていません。
Swift 利用者への影響
- アプリのサイズとメモリ使用量が下がります。 value functions の縮小やランタイムの改善により、特に型を多く宣言する SwiftUI アプリでバイナリサイズと heap メモリ使用量が減ります。
- ボイラープレートが減ります。
@mainでエントリポイントを型として定義でき、enumのComparable自動合成や複数パターンのcatchなどで定型コードを減らせます。 - クロージャまわりの記述が読みやすくなります。 複数の trailing closure により、複数のコールバックを取る API を簡潔に書けます(SwiftUI などの宣言的 API とも相性が良い書き方です)。
- エディタと診断の体験が向上します。 コード補完が最大 15 倍速くなり、SwiftUI を含むコードのエラーメッセージがより正確になりました。
- パッケージで配布できるものが広がります。 SwiftPM がリソース・ローカライズ・XCFramework・条件付き依存をサポートし、ライブラリとして配布・再利用できる範囲が広がりました。
関連リンク
- 前のリリースについては Swift 5.2 リリース を参照してください。
- このリリースの計画と管理方針については Swift 5.3 のリリースプロセス を参照してください。
release/5.3ブランチは、次のリリースに向けた変更を蓄積するため引き続き開かれた状態に保たれました。 - 本記事に関連する解説記事: 新しい診断アーキテクチャの概要
- 本記事で触れた Proposal ダイジェスト:
- Swift のダウンロード
- Swift Package Manager