ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Xcode 16の新機能
Xcode 16における、生産性とパフォーマンスに関する最新の改善ポイントについて解説します。コード補完、診断、Xcodeプレビューなどの機能強化のほか、ビルドにおける変更点の詳細や、デバッグ機能とInstrumentsの改善点についても学ぶことができます。
関連する章
- 0:00 - Introduction
- 0:29 - Updates in editing
- 0:33 - Code completion
- 1:01 - Adopting Swift 6 data-race safety guarantees
- 2:49 - Improvements to Previews
- 6:22 - Updates in builds
- 6:26 - Explicit modules
- 7:15 - Package resolution
- 7:15 - Package resolution
- 8:30 - What's new in debugging
- 8:35 - Build process and debugging
- 9:07 - Thread performance checker
- 9:23 - The organizer
- 12:16 - The RealityKit debugger
- 12:55 - Meet Swift Testing
- 18:42 - What's new in Instruments
- 19:44 - Meet the flame graph
- 21:38 - Wrap up
リソース
関連ビデオ
WWDC24
-
ダウンロード
こんにちは Daisyです 同僚のJakeとともに Xcode 16の新機能を いくつか紹介します さっそく始めましょう アプリ開発のすべての段階で Xcodeを使うことができます Xcode 16の新機能として Swiftコードの編集 ビルドの実行 コードのデバッグとテスト パフォーマンスの最大化があります コード編集の3つの新機能から 見てみましょう
まず SwiftおよびApple SDK向けに 特化してトレーニングされた オンデバイスコーディングモデルにより コード補完でより適切なコードが 提案されるようになりました
関数名やコメントなど周囲の コードコンテキストを使って アイデアをすばやく形にします
これは すべてAppleシリコンで実現しており macOS SequoiaでXcode 16を 実行する時に利用できます
次にSwiftです Swift 6には 並行処理の安全性を保証する 新しい言語モードが導入されています これにより 通常 実行時にのみ 発生するデータ競合が コンパイル時の問題になります これは コードの正確性と安全性を 向上させる優れた方法です このような保証を活用するために Swift 6の言語モードを 採用することをお勧めします ただし Xcode 16をすぐに使い始めて 今後提供される各言語機能の警告を 段階的に有効にすることもできます その方法を紹介します
BOT-anistというアプリを例に 説明します ロボットが植物を育てるアプリです このアプリをSwift 6に 対応させましょう まず の に移動します
ここで 今後提供されるコンパイラ機能を 1つずつ有効にできます
を にしてみます
ビルドすると Xcodeの問題ナビゲータに 新しい警告が表示されます
グローバル変数loggerを並行処理で 安全に扱えないことを示しています
この問題をクリックすると loggerの定義にジャンプします
loggerはミューテーションの必要がないので varからletに変更できます これでデータ競合から保護されます
今後提供される機能を採用することで Swift 6に切り替える前に潜在的な 問題を見つけて対処することができます Swift 6では これらの警告が エラーとして表示されます
準備ができたら で Swiftの言語バージョンを設定します
詳細は「Migrate your app to Swift 6」をご覧ください
Xcode 16ではPreviewsも 大幅に改善されています
Previewsを使うと UIを迅速に確認して 優れたUIを作成できます 新しく追加された2つのAPIによって コードの記述がシンプルになり 再利用性も高まり モデルとの統合性が向上します
1つ目はPreviewableマクロです Stateなどのプロパティラッパーに Previewableをアタッチすることで プレビューブロック内で プロパティラッパーを直接使用できます ラッパービューを記述する 必要がなくなります アプリで例を見てみましょう
このRobotFaceSelectorViewは ロボットの顔へのBindingを取ります
プレビューを作成する時 プレビュー本文にStateを直接定義して Previewableマクロをアタッチできます これでプレビューシステムに ラッパービューの作成を指示できるので 私が作成する必要はありません
次にビューを追加します
わずか数行で実際の UIを確認できます
もう1つの新しいAPIは PreviewModifierです PreviewModifierを使うと プレビュー用の 環境やデータを簡単に共有できます これにより コードの重複が減るだけでなく プレビューシステムがデータを キャッシュできるようになります 別のViewで説明します RobotNameSelectorViewを 機能させるにはRobotNamerが必要です
この型はロボットの名前候補を サーバから非同期に取得します ただし プレビューを作成する際に何度も サーバにアクセスする必要はありません PreviewModifierを使うと 外部サーバにアクセスせずに すべてのプレビュー用の RobotNamerを作成できます
まず PreviewModifierに 従う型を定義します
このプロトコルには2つの要件があります まず makeSharedContextを使って データを読み込み 保存します このメソッドは非同期かつ 例外をスローするので データを非同期に読み込んで エラーを処理できます ここでは ローカルファイルから名前を 取得してRobotNamerを作成するので 外部サーバにはアクセスしません
重要なのは プレビューシステムが このデータをキャッシュするため 同じ型のすべてのモディファイアについて このメソッドが1回しか 呼び出されないことです
2つ目の要件はbodyメソッドです bodyメソッドを使用すると プレビューを 共有コンテキストでラップできます ここではenvironmentモディファイアを 使用してRobotNamerを渡します
モディファイアを定義したら あとは 特性を使ってプレビューに提供するだけです ただし このモディファイアを何度も使うので PreviewTraitで extensionを定義して 呼び出し側のコードを減らします あとはプレビューを作成するだけです
この場合は比較的シンプルですが 例えば SwiftDataの ModelContainerを使って プレビュー間でデータを 共有する必要がある場合 PreviewModifierは特に役に立ちます
これらのAPIだけでなく 今年はPreviewsの パフォーマンスと基盤が大きく進歩しました 新しい実行エンジンにより Previewsは これまで以上に高速になりました
コンパイラ ビルドシステム オペレーティングシステムの進化により Previewsはプロジェクトで 同じビルド製品を使用し プログラムをその場で再アセンブルするので 別のコピーを作成する 必要がなくなりました Previewsはビルドに関する 今年の改善点の1つです 他の改善点について Jakeに説明してもらいます ありがとう Daisy では ビルドについて説明します
Xcode 16では 明示的なモジュールにより ビルドが飛躍的に向上します この機能は 並列処理の向上より 優れた診断機能 デバッグの高速化を コードを1行も変更せずに実現します
この信じられない機能はどう使うのでしょう CとObjective-Cでは 明示的なモジュールは デフォルトでオンになっています Swiftの場合 オプトインが必要です 試してみましょう
に移動して
を 有効にします
ビルドを開始します
ところで Xcode 16でのSwiftパッケージ 統合の改善に伴い 最初にパッケージの依存関係が 解決されるまで待たなくても ビルドをキューに入れることができます 素晴らしいですね では 今 何が起きているのでしょうか 明示的なモジュールを使用すると Xcodeは各コンパイル単位の処理を 3つのフェーズに分解します
スキャン モジュールのビルド そして元のコードのビルドです
最初の2つのフェーズは ビルドログにと コマンド または コマンドとして表示されます 以前 これらの操作はソースファイルの コンパイルの一部として 暗黙的に実行されていました 今回の改善で ビルドの内容が より詳細になり 並列処理が改善され モジュールの問題で ビルドに失敗した場合の エラーメッセージもわかりやすくなりました
明示的なモジュールは ビルドタイムラインにも反映されます これにより ビルドプロセスで時間が かかっている場所を確認しやすくなり ビルドの最適化に役立ちます
詳細は「Demystify explicitly built modules」をご覧ください
さて コードを書いてビルドしたので デバッグしてみましょう
最初に ビルドプロセスでデバッグを改善する いくつかの方法を説明します 明示的なモジュールを使うと 式の評価時に lldbがビルド出力を 再利用できデバッグが高速になります また macOS、Sequoia、iOS 18を 展開ターゲットとしてビルドする時 DWARF5がデフォルトのデバッグ シンボルフォーマットになりました DWARF5では dSYMバンドルが小さくなり シンボル検索が高速になります
Xcode 16での実行時 Thread Performance Checkerが さらに多くのことを行います メインスレッドのハングや優先順位の 逆転を検出するだけでなく 過剰なディスク書き込みや低速な アプリ起動の診断が表示されるため アプリのパフォーマンス向上に役立ちます
Organizerには アプリ起動の診断ログに関する 新しいカテゴリが追加されています ユーザーデバイスでアプリの 起動に時間がかかる場合 最も処理が遅いコードパスのシグネチャが Xcodeに表示されるため 影響が大きい問題の解決に 優先的に取り組むことができます
ディスク書き込み診断に 精通している方には この新しいアップデートを 気に入ってもらえるでしょう Organizerでアプリのバージョン間で 問題の影響がどのように変化したかを 確認できるようになりました
ビューを開くと 一部のシグネチャに 上向き矢印が付いています これらの矢印は ユーザーへの影響が大きい問題に 優先順位を付けるのに役立ちます
問題をローカルで再現できなくても コードのデバッグ中に Thread Performance Checkerは 最も大きな問題を ランタイムエラーとして表示し 注目すべきコード行を正確に特定します
この例で Thread Performance Checkerは ユーザーに影響がある問題を指摘しています このビデオアセットをメインスレッドで 読み込むべきではないようです
Xcodeを開いてブレークポイントを設定し これを追跡します 次に 問題のあるファイルを開きます
ガターをクリックして ブレークポイントを設定し 実行します
ブレークポイントに到達しました この呼び出し元を トレースしやすくするために デバッグバーで Unified Backtrace Viewを有効にします
この新しい可視化により コールスタックを追跡でき 各フレーム内でスクロールして 周囲のコードを確認できます
変数にカーソルを合わせて 値を確認することもできます
Viewのbodyメソッドのコードに await呼び出しがあります
この呼び出しをトレースしました アプリ内からの呼び出しです
このビデオプレーヤーの 初期化関数は非同期のようで SwiftUI taskモディファイアから 呼び出されているようですが 外側のSwiftUIビューから @MainActorコンテキストを継承し メインスレッドでI/O実行しています nonisolatedを指定して この問題を修正します
これでうまくいくはずです
Unified Backtrace View Thread Performance Checker 新しいOrganizerの レポートのおかげで Xcodeでは最も重要なことに集中できます 新しいRealityKitデバッガを使うと 3Dアプリの開発も はるかに簡単になります ボタンをクリックして 実行中のアプリのエンティティ階層の スナップショットをキャプチャし Xcode内で3Dを確認できます このデバッガではエンティティと そのコンポーネントを表示して 組み込みプロパティとカスタムプロパティの 両方を確認できます
RealityKitデバッガや 既存デバッガの詳細は 「Break into the RealityKit debugger」 「Run, break, and inspect: Explore effective debugging in LLDB」をご覧ください
次に Daisyがテストについて説明します
Jake ありがとう デバッグが開発中に 問題を解決するのに役立つように テストは アプリの新しい問題や バグの再発を検出する優れた方法です
Swift TestingはSwift言語の機能を 活用した新しいフレームワークであり 表現テストがより強力かつ簡潔になります これらのテストは既存のXCTestと 組み合わせて利用できます Swift Testingの例を示します
私たちのチームはBOT-anistに 新しい機能を追加しています ロボットに新しい植え付けスタイルと アニメーション状態を追加します まだテストが完了していません 新しいテストを追加しましょう
まず testフォルダに 新しいファイルを作成し PlantTestsという名前を付けます
テストを作成するため Testingフレームワークと アプリをインポートします 次にplantingRosesという 名前の関数を記述します この関数には好きな名前を 付けることができます Swift Testingのすべての機能を 活用するために必要なのは Testマクロを追加することだけです
Testマクロを追加するとすぐに Xcodeはこれがテストであると認識し ナビゲータに表示されます
このテストでは バラのデフォルトの植え付けスタイルが 接ぎ木であることを確認します まず rose型のPlantを作成します
次に rose型のPlantをもう1つ作成し 明示的なスタイルとして 接ぎ木を指定します
必要なものを記述できました 最後にexpectマクロを使用して 両者が同じことを確認します このマクロは任意のブール式を取ります これを使って文字列や浮動小数点数などの 型を検証できます
テストを実行しましょう
おや テストが失敗しました テストは この2つのバラが 異なることを示しています エラーの説明では 両者は同じように見えます 同じ絵文字が表示されています ただし 他のプロパティの 状況がわかりません
Swift Testingでエラーの をクリックすると 各値の追加情報が表示されるので 詳細を確認できます なるほど 植え付けスタイルが異なります テストを作成してデフォルト値を確認し 簡単に解決できました
.seedlingを .graftに修正しましょう
もう一度テストを実行してみます Quick Actionsを使用します ショートカットcommand + shift + Aで Quick Actionsを表示します
「test again」と入力して このテストを再実行します
うまくいきました Testマクロは関数をテストに 指定するだけではありません 様々な特性を使って 情報を追加したり 動作を変更したりできます 例えば 表示名や引数を テスト関数に渡すことができます
このテストはロボットのアニメーションの 状態マシンをチェックします
状態がcelebrateに移行するのを 確認するのが目的です 複数のテスト関数を記述する代わりに 状態のリストをTestマクロに渡します 状態をパラメータとして受け取る 1つのテスト関数を使います
パラメータ化したテストを実行します
Swift Testingでは 指定された各引数を 独自のテストケースとして並列に実行します ナビゲータに個々のケースが表示され どれが失敗したかを示してくれます 植物のアニメーションの状態に 問題があるようです 有効な状態遷移として .celebrateを追加し忘れていました 修正しましょう
隣にあるボタンを押すと 失敗したケースだけを再実行できます
すべてのテストケースがパスしました XcodeにおけるSwift Testingの もう1つのメリットはタグによる整理です Swift Testingでは タグを作成して 様々なスイートのテストを グループ化できます この機能を使うことで 関連するテストを把握できます まず Tag型を拡張して カスタムタグplantingを含めます
次に ラベルを付けたいテストの Testマクロにタグを追加します このテストに追加します
plantingRosesにも追加します
適用したタグはナビゲータのタグビューに グループ化されて表示されます
タグ内のすべてのテストを実行するには 横にあるボタンをクリックします タグを使うと テストプランから テストを除外することもできます
ナビゲータの一番上の を選択して テストプランに移動します
新しい植え付けとアニメーションの 機能はまだ開発中です これらのテストの影響でCIが 不安定になるのは避けたいです そこで 機能が有効になるまで この機能のタグを 除外タグのリストに追加します
Swift Testingの詳細は 「Meet Swift Testing」と 「Go further with Swift Testing」 をご覧ください
コードのデバッグとテストが完了しました テストは高速ですが アプリは違うようです Jakeに見てもらいましょう ありがとう Daisy テストを実行して アプリの機能を確認しました ですが 実際に動かすと 思っていたよりも起動に時間が かかることに気づきました
パフォーマンスの問題の診断に 最適なツールはInstrumentsです XcodeのProfileアクションから アクセスできます Time Profiler Instrumentを 使って Daisyが記録したアプリの 起動のトレースがあります このInstrumentはコードの CPU使用率を可視化し 実行にかかった時間を測定できます 実際に見てみましょう
CPU使用率が非常に高いですね 初期の起動時に長時間ハングしています この場合の対処方法を説明します 原因を理解するために まず 調査範囲を ハング間隔に設定します
トレースの一部だけを見ているので データを分析してみましょう
問題を絞り込むために Instruments 16の 新しいフレームグラフを使います Jump Barから起動できます フレームグラフは トレース実行の 概要を示すもので 問題を一目で特定できます 実行間隔は トレース中にかかった 時間の割合によって重み付けされ 左から右へソートされます つまり グラフの左側には 最も多く実行されるコードが 常に表示されます プログラムの実行内容を見てみましょう
実行時間のほとんどが この読み込み関数にかかっているようです
この関数はSwiftUI Viewの bodyから呼び出されています ここに問題があるようです
このフレームを右クリックして を選択します コードに直接移動できます
なるほど 問題がわかりました 大量のアセットをループ内で 順に読み込んで メインスレッドで実行しています これはよくありません タスクグループを使って 読み込みを並列処理しましょう この作業の実行はそれが属する バックグラウンドに移動されます
再ビルドします Instrumentsで 新しいTime Profileを取得して 効果があったか確かめます
いいですね 起動が非常に高速になりました フレームグラフでわかるように アセットの読み込みが複数の バックグラウンドスレッドに分散され メインスレッドがブロックされません
フレームグラフは コールツリー木を使用する すべてのInstrumentで機能します コールスタックを視覚的に確認する この方法は 問題の発見に有効であり アプリのプロファイルを定期的に 取得するもう1つの理由です
これらはXcode 16の魅力的な 新機能のほんの一部です ここで説明した内容や高速なUIプレビュー 強化されたC++ランタイム ローカリゼーションワークフローなどの 改善点の詳細は developer.apple.comで リリースノートをご覧ください Xcode 16をダウンロードして 試すこともできます ありがとうございました WWDCをお楽しみください
-
-
3:37 - Inline State within Preview
#Preview { @Previewable @State var currentFace = RobotFace.heart }
-
3:45 - View using Inline State
RobotFaceSelectorView(currentFace: $currentFace)
-
3:53 - Complete Preview using Previewable
#Preview { @Previewable @State var currentFace = RobotFace.heart RobotFaceSelectorView(currentFace: $currentFace) }
-
4:40 - Type Conforming to PreviewModifier
struct SampleRobotNamer: PreviewModifier { typealias Context = RobotNamer static func makeSharedContext() async throws -> Context { let url = URL(fileURLWithPath: "/tmp/local_names.txt") return try await RobotNamer(url: url) } func body(content: Content, context: Context) -> some View { content.environment(context) } }
-
5:29 - Extension on PreviewTrait
extension PreviewTrait where T == Preview.ViewTraits { @MainActor static var sampleNamer: Self = .modifier(SampleRobotNamer()) }
-
5:38 - Preview using created PreviewModifier
#Preview(traits: .sampleNamer) { RobotNameSelectorView() }
-
10:26 - AVPlayer Creation
struct BOTanistAVPlayer { func player(url: URL) throws -> AVPlayer { let player = AVPlayer(url: url) return player } }
-
11:28 - AVPlayer Call Site
self.player = try? await robotVideoAVPlayer()
-
11:57 - AVPlayer Initialization
private nonisolated func robotVideoAVPlayer() async throws -> AVPlayer? { guard let url = Bundle.main.url(forResource: RobotVideo.resource, withExtension: RobotVideo.ext) else { throw BOTanistAppError.videoNotFound(forResource: RobotVideo.resource, withExtension: RobotVideo.ext) } let avPlayer = BOTanistAVPlayer() let player = try avPlayer.player(url: url) return player }
-
13:42 - Initial Test Scaffolding
import Testing @testable import BOTanist // When using the default init Plant(type:) make sure the planting style is graft @Test func plantingRoses() { // First create the two Plant structs // Verify with #expect }
-
14:36 - Complete Test
import Testing @testable import BOTanist // When using the default init Plant(type:) make sure the planting style is graft @Test func plantingRoses() { // First create the two Plant structs let plant = Plant(type: .rose) let expected = Plant(type: .rose, style: .graft) // Verify with #expect #expect(plant == expected) }
-
17:35 - Custom Tag
extension Tag { @Tag static var planting: Self }
-
17:42 - Tag Usage in @Test
.tags(.planting)
-
20:37 - Slow Asset Loading
for asset in allAssets { asset.load() }
-
20:54 - Fast Asset Loading
await withDiscardingTaskGroup { group in for asset in allAssets { group.addTask { asset.load() } } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。