ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Xcodeの基本
編集、デバッグ、コミットし、反復するプロセスを加速。アプリ開発におけるイテレーションを高速化する、Xcodeの各種ツールをご紹介します。開発ワークフローの最適化と強化に役立つヒントやコツもお教えします。
関連する章
- 0:00 - Introduction
- 1:31 - Find the right content
- 1:45 - Filter navigators
- 3:05 - The Find navigator
- 5:43 - Move between files
- 5:47 - The tab bar
- 7:41 - The jump bar
- 8:38 - Tricks for creating new files
- 9:34 - Warnings and error annotations
- 10:42 - Using bookmarks
- 10:56 - Using Mark comments
- 11:15 - Leverage shortcuts
- 11:22 - Open Quickly
- 12:12 - Useful commands and shortcuts
- 14:19 - Code completion
- 15:10 - VIM mode
- 15:25 - Common emacs commands
- 15:43 - Get the most out of git
- 15:47 - Show the last change for a line
- 16:07 - Changes navigator
- 16:55 - Debugging
- 17:21 - Setting breakpoints
- 21:40 - Using the console
- 23:01 - Testing
- 23:51 - Test Navigator
- 26:09 - Running tests
- 27:42 - Using Test plans
- 28:38 - Code coverage
- 29:36 - Explore the Test report
- 30:23 - Distributing your app
- 30:48 - TestFlight
- 31:26 - Archiving
- 33:26 - Explore the Organizer
- 35:41 - Wrap up
リソース
- Forum: Developer Tools & Services
- Including notes for testers with a beta release of your app
- Testing
- Xcode updates
関連ビデオ
WWDC24
WWDC23
WWDC22
Tech Talks
-
ダウンロード
ソフトウェアエンジニアの皆さん こんにちは XcodeのプロジェクトマネージャーMykeです XcodeチームのデザイナーCheechです Apple SDKのベテランのデベロッパから このプラットフォームでの開発が 初めての方まで Xcodeで効率よく作業するための基本を 説明します 開発サイクルを迅速に 明確に そして楽しく 進めることができるようになります 私たちは日々 編集 デバッグ テスト コミットを繰り返しています プロジェクトが始まったばかりの頃は このサイクルは短く 調査もわずかです しかし プロジェクトやチームが 拡大したときや 新しいチームへの参加時には バランスが変化し 問題に取りかかること自体が むしろ問題の半分を占めるようになります 機能を追加したり バグを修正したりするには 適切な場所で適切な変更を行うために より多くの調査が必要です 幸いなことに Xcodeには多数の機能があり 新しい変更を行うために 必要なコードがすぐ見つかります まず 編集をより迅速に行う方法を説明します その後 Mykeが変更のデバッグと テストについて説明します アプリを公開する準備が整ったら 配信を行います Xcodeにはたくさんの機能があり パワフルなものも多く含まれています それらの機能を活用して ファイル間を簡単に移動し 編集対象のコードを 見つける方法を学びましょう ここでは Xcodeの最も強力な キーコマンドについて学び Gitを最大限に活用するためのコツを いくつか紹介します まずは適切なコンテンツを 見つける方法を見てみましょう Xcodeを 初めて開いたとき 「たくさんの機能がある」と 驚かれるかもしれません そのとおりです Xcodeには初めから 開発サイクルの迅速な反復に必要な機能が すべて組み込まれています インターフェイスの左側にナビゲータがあり それぞれ異なる視点で プロジェクトを確認できます このビューでは プロジェクトナビゲータが選択されていて プロジェクトのファイル階層が 表示されています 新しいファイルを作成して コードを記述するという流れの中で ナビゲータが雑然としていると感じたら まずはフォルダを1つか2つ 追加することをお勧めします それから フォルダを見つけられるように 画面下部のバーにファイル名を入力します 前に触れた強力な機能を 覚えているでしょうか 実は 多くのナビゲータには 特別なフィルタが付いています 入力を開始して テキストがこれらの いずれかのフィルタに一致すると 入力の上にメニューが現れて ターゲット名によるフィルタリングなどの 機能を追加で利用できます 画面下部のバーの右側に表示されるアイコンも ナビゲータによって変わります 右端にあるアイコンをクリックすると ファイルがGitのステータスで フィルタリングされます 次に行うコミットで使用するファイルに 簡単に戻ることができると同時に プロジェクト全体のコンテキスト内で それらを表示することができます コミットに関して不安がある場合は Xcodeで このフィルタを使用してコミット前に変更を 簡単に確認できます フィルタリングは ファイル名が明らかな場合には便利ですが ファイル名が思い出せないときは どうすればよいでしょうか 現実的でない状況だとは思いますが 仮定してみましょう この状況では Xcodeの Find Navigatorをお勧めします command + shift + Fで移動できます Find Navigatorでは プロジェクト全体を 検索することができます 検索結果が少ない場合は それだけで必要な結果がすべて得られます その一方で プロジェクト全体に現れる 何かを探していて 検索結果の絞り込みが 必要な場合もあります これは私にもよくあることです 幸いなことにXcodeにはその機能があります 目的の結果を素早く見つけるためのツールを いくつか紹介します 画面下部のバーだと思われた方は正解です プロジェクトナビゲータと同様 画面下部のバーを使用して 検索の絞り込みができます 一致する行に対しさらに別の単語を指定して フィルタリングしたり ファイル名を指定して そのファイルの結果を確認してみてください 検索対象がはっきりしない場合は ナビゲータのコンテンツを操作する 便利な方法がいくつかあります テキストの一致を見る前に ファイル名をスキャンする場合は commandを押しながら ファイル名の左にある 開閉用の矢印をクリックして その関連ファイルをすべて折りたたみます これはXcodeの すべてのアウトラインビューで機能します ここで 最初の3つのファイルの 「padding」は変更しないことにして 3つのファイルを検索対象から除き より関連性の高いファイルに的を絞ります これらのファイルを選択し deleteキーを押して削除します ご安心を コードが全部消えたわけではありません これらのファイルはまだ存在していますが 現在のクエリからは隠されています これで 注目すべき結果に集中できます このように クエリで多数の一致が検出されるものの 特定のグループのファイルにのみ 注目したい場合は 検索フィールドの下のメニューを使用して 検索対象を絞り込みます 編集中のファイルを含む 任意のグループを選択できます を選択し 別のグループを選んだり 複数のグループを選ぶことができます 同じ検索範囲を頻繁に使用する場合は その範囲を保存しておくと ナビゲータの 初期メニューに表示されるようになります Xcodeの シンボルインデックスを フィルタリングするには 検索フィールド上のをクリックして 開くメニューから行います はクラス階層の概要を 把握するのに最適です 検索フィールドに何かをコピーして 貼り付けようとしたものの すでに重要な情報を コピーしていたことに気づいて その情報が永遠に失われてしまったことは ありませんか? 幸い macOSには解決策があります テキストを選択した状態で command + Eを押すと そのテキストが検索フィールドに入力され クリップボードはそのままです これは どのmacOSアプリでも機能します 便利ですよね
さて 適切なコンテンツを見つけるための フィルタリングと検索の方法を確認しました 次は ファイル間の移動に役立つ便利な方法を いくつか紹介します まずは タブバーです これはソースエディタの上部付近 ツールバーの下に位置しており ドキュメントを切り替えるのに とても便利です ここまで多数のファイルを見てきましたが 今タブバーにあるタブは4つだけです なぜでしょうか それは Xcodeに 2種類のタブがあるからです 1つは永続的なタブで コード編集など明示的に関心を示した ドキュメントに使用されます もう1つは暗黙的なタブで 通過しただけのファイル用に Xcodeが作成します ファイルを出るとこのタブは消えます 暗黙的なタブは タイトルがイタリック体で表示され 他のタブと区別できます 編集せずに タブを永続的にしたい場合は コンテキストメニューから を選択するか タブをダブルクリックします 作業が済んで 多数のタブを同時に閉じるには タブを1つひとつ閉じるのではなく 1つのタブの終了ボタンを クリックしてみてください 他のタブとまとめて閉じられるため便利です タブバーの左にある 戻るボタンと進むボタンの機能は 見た目のとおりで 戻ったり進んだりすることができます ここで どちらかのボタン 例えば戻るボタンを長押しすると 詳細な履歴が表示されます ボタンを何十回もクリックしなくても 目的の場所に即座にジャンプできます 戻るボタンの左には 関連ファイルメニューがあります 名前から 機能の想像がつきますね 最近使用したファイルのリストです また テキストに基づいて 現在のクラスのサブクラスや 現在の関数の呼び出し元など 各種のシンボリック関係が表示されます ここにはいろいろな機能があるので 確認していきましょう タブバーの右側にある3つのボタンは エディタのUIを設定するためのものです 真ん中のボタンで エディタのレイアウトを コントロールできます SwiftUIのプレビュー エディタミニマップ 注釈やコードカバレッジなどの 行アクセサリを追加できます ときどき ナビゲータに重要な情報が すでに表示されていて それを維持したい場合があります 前に出た検索クエリを 覚えているでしょうか それでも 関連ファイル間を ジャンプする必要があります タブバーを使うこともできますが ジャンプバーを使用することもできます タブバーのすぐ下にあるジャンプバーは 現在のファイルへのパスを示します このパスの各ステップは インタラクティブです 項目をクリックすると 隣接するファイルが表示されます このリストは膨らむことがあり 私のように 多項目のメニューでの移動に 迷うことがあるかもしれません 入力を開始すると メニューの最上部に フィルタフィールドが現れます ご想像のとおりメニューをフィルタできます この機能は Xcodeの多くのメニューに付いているので ぜひ試してみてください プロジェクトナビゲータのジャンプバーから 項目を見つけるには command + shift + Jを押します 現在のファイルの近くに新しいファイルを 作成したいときに使ってみてください Xcodeには 新規ファイルの 作成方法が多数あります テンプレートは選択せずに 任意の場所を右クリックして 空のファイルを作成できます 既存のファイルのフォーマットを使用して ファイルを新規作成する場合は 昔ながらのコピーペーストや複製を 使用します 私が好きな方法は optionキーを押しながら 項目をクリックしてドラッグし コピーするやり方です 私はすべてにoptionドラッグを 使用しています ファイルが大きくなりすぎることがあったら その一部をカットして クリップボードに貼り付けられます command + Xを使用し ナビゲータの任意の場所を右クリックします optionキーを長押しすると 一部のメニュー項目が変わります を選択します optionキーの長押しで表示される 代替メニューオプションも Macの優れた機能です 便利ですね コンテンツをナビゲータに直接 ペーストして 新しいファイルを Xcodeに作成させることもできます もちろん滅多にないことですが コードに誤りがある場合は 該当する行に Xcodeによって 警告またはエラーの注釈が付けられます これらの注釈はインタラクティブです 表示されている他に情報がある場合は クリックすることで 残りの情報が表示されます 1つの行に2つ以上の問題がある場合は クリックして開きましょう コンパイラにFix-itが表示される場合も クリックして開いてください をクリックすると 修正が適用されます
Fix-itは コード記述中の構文エラーに対する 修正を提案する機能です 問題がグレーに変わったら 問題が最後に更新されてから ファイルが変更されたということです 問題が消えたら問題解決です もし残っていたら また問題に取り組む必要があります 実は タスク管理の一環として 独自の警告を挿入できます 「#warning」のマークと メッセージをエディタに入力します
未読のテキストメッセージが238件もあると どうなるかわかりますね エラーの注釈は大量になるでしょう 私はきれいな状態の方が好みです ブックマークは便利です エディタ内の任意の場所を右クリックして ブックマークを行に追加できます これはタスクを個人的に管理するのに 優れた方法です ブックマークナビゲータを使って チェックできる点も便利です より永続的な注釈が必要なときは ファイルにMarkコメントを 追加してみてください これはセクションタイトルとして機能し ミニマップと エディタコンテンツの ジャンプバーセグメントに表示されます 以上のように本当にたくさんの方法で ファイル間を移動できます 何かしら 新しい情報があったなら幸いです ここまで いくつもキーコマンドが 出てきましたが なんと Xcodeには利用可能な ショートカットがまだまだあります Open Quicklyは Xcodeが持つ まるでテレポートのような機能です 地点Aと地点Bの間を最速で移動できます 任意の場所で command + shift + Oを押して ファイル名またはシンボル名の一部を 入力するだけで 即座に開いて 移動先のリストがすぐに表示されます コード補完と同様の一致ルールを 使用しているため 移動先の名前として 任意の一意の単語を入力して その場所に即座に移動できます スラッシュをクエリに含めると ファイル名ではなくファイルパスで 検索できます また クエリの末尾に コロンと行番号を入力し 特定の行に移動することもできます ファイルを別々に開きたい場合も あると思います optionキーを押しながら returnキーを押すと 2つのファイルを横並びで 表示することができます Xcodeのナビゲーション設定を確認して 修飾子の動作をカスタマイズしましょう Xcodeには数多くの強力なコマンドがあり 新しいものを作成するためのキーが 足りないくらいです お気に入りは覚えていますが その他のものは メニューを見て探すのではなく クイックアクションを使用します これは command + shift + Aを押すと 開きます クイックアクションでは 自然言語で Xcodeのコマンドを検索できます Xcodeの設定ペインの タブを操作して たくさんあるXcode独自のコマンドを 確認したりカスタマイズしたりできます チームで人気のコマンドを いくつか紹介します まずはです commandキーを押しながらクリックで 呼び出せます 関数や型の定義に移動するコマンドです optionキーを押しながらクリックで です クリックしたシンボルのドキュメントや Swift変数の推測される型を表示できます を呼び出すには テキストを選択した状態で command + control + Eを押します シンボルの名前を 現在のファイルに出現する 全部について変更します 右クリックでを選択すると 現在の関数の呼び出し元を すべて表示できます 関数呼び出しが実行されているときに 「control + M」を押すと 多数の行に形式が整えられます 組となる丸括弧 角括弧 引用符がある場所を 特定したいときは 一方をダブルクリックすると 他方にジャンプできます optionと矢印キーを使用すると 単語単位で移動できます また controlと矢印キーを使用すると サブワード単位で移動できます 行の冒頭または末尾への移動に Homeキーと Endキーをよく使用している方には command + 左キー または右キーが便利です こうしたテキスト移動コマンドは ソースエディタのマルチカーソル編集 機能とともに 欠かせないものです 同じswitch文やイニシャライザを 何度も作成したり 同じ操作を多数の行で行う必要が あったりしないでしょうか control + shiftを押しながら クリックすることで 複数の場所にカーソルを挿入して 同時に複数の文を作成できます
いくつかの場所に同様のコードを 追加する必要がある場合は コード補完で表示される 同じプレースホルダで テンプレートを作成できます それにはこれらの文字で テキストを囲みます Xcodeのコード補完は 数語しか覚えていなくても コードを完成させるのに役立ちます Xcode 16では 予測的な補完機能によって 周囲のコードに基づいて 文やメソッド全体が提案されます これらの補完内容は コードにインラインで表示されます 表示された内容を受け入れるには tabキーを押します また optionキーを長押しすると 予測内容の全体が展開されます すべての内容を受け入れるには optionキーとtabキーを同時に押します プロのヒントを紹介します ユーザーのコメントと変数名は 役立つ情報として予測に利用されます ユーザーの表現が豊富であるほど 予測はより正確なものになります 補完ウィンドウでは 狭い領域に 多くの機能が盛り込まれています ウィンドウの最下部で メソッドの完全な型シグネチャを 確認できます 補完の選択時に optionキーを押したまま enterキーを押すと すべての引数を受け入れられます これまでvimを使ったことがある方は 手放せないツールだとわかると思います Xcodeでは メニューで vimモードを容易に切り替えられます Xcode 16では もう1つの マルチカーソル編集手段として vimの繰り返しコマンドを サポートしています 矢印キーを使用せずに 行の周囲を移動できるかもしれません Xcodeはさらに macOSのネイティブなテキスト編集操作を 全部サポートしています control + A、E、Pなど 基本のEmacsコマンドを始めとして その他多数の操作がサポートされています 次は Gitを最大活用するための ちょっとしたコツをいくつか見てみましょう 例えばエラーの修正中だとして エラー発生に至った過程を 詳しく知りたいとします 右クリックして を選択します その行のコミットの概要が表示されます これはblameの詳細版のようなものです 問題を招いたのは自分だとわかるので 覚悟しておきましょう コミットする前に 全部の変更を確認する準備が整ったら 変更ナビゲータで 実行予定のコミットをプレビューします 変更のステージング コミット そして昼食の前に 進行状況を把握する時間を取りましょう Xcodeでの編集作業を 高速化する方法をおさらいしましょう 適切なコンテンツを見つける方法として ナビゲータでのコンテンツのフィルタリングと Find Navigatorの使用を紹介しました コード内の注釈とともに タブバーとジャンプバーを使用して ファイル間を移動する 新しい方法を学びました 簡単迅速に開くアクションなど 多数あるXcodeのショートカットを 忘れずに利用しましょう 最後に Gitを使用する際のコツを いくつかお話ししました 次はMykeにバトンタッチして デバッグについて話してもらいます Cheech ありがとう デバッグでは 変更すべき 適切なコードを見つけることが重要です 問題の行は明らかでも 原因がわからない そんなことがよくあります コードが何百回も実行された後に 問題が発生することもあります ときには 一見して問題ないバグが 非常に遠い場所のエラーの原因に なっていることがあります ブレークポイントを使用する際のコツを いくつか紹介します また print文を使用したデバッグを より効果的に行う方法を説明します まず 特に記述量の多いコードで 問題の切り分けに役立つ ブレークポイントの機能を いくつかお見せします 単純な場合は 行番号をクリックして ブレークポイントを追加すれば プログラムはその行で停止します ブレークポイントに到達する回数が多すぎて 実用的でない場合には 次の方法を試してみてください 2つのブレークポイントを連携させて 使用できます 何度も実行される高頻度関数があるとして それはアプリでボタンを クリックした直後にも実行され その呼び出しだけが 問題になっているとします ボタンハンドラに ブレークポイントを追加し 高頻度関数に 2つ目のブレークポイントを追加します 高頻度関数のブレークポイントを 2回目にクリックして無効にします プログラムの実行時 ボタンハンドラの ブレークポイントに到達したら 高頻度関数のブレークポイントを 再度有効にして 続行します これで アクセス回数の多い2つ目の ブレークポイントに 正しい状態で到達します ブレークポイントは使い終わったら 外にドラッグして削除できます 処理が予期せず失敗し Swiftのエラーが発生する場合は エラーの発生元を特定するのが 困難なことがあります ブレークポイントナビゲータで 「Swiftエラーブレークポイント」を追加し catchではなくthrowで停止できます エラーが発生した場所で即座に アプリが停止します 予想されるエラーの発生とキャッチが アプリで定期的に行われる場合 このブレークポイントはやや 活発すぎるかもしれません Swiftエラーブレークポイントの 範囲を測るため ブレークポイント有効化テクニックの使用を 早い段階で検討してください これら高頻度関数の中には 関心のあるケースを ノイズからフィルタするのに 十分な情報があるものもあります 例えばこの関数は 特定の接続型でのみ 失敗することがわかっています ブレークポイントをダブルクリックして 編集し その接続型の条件を追加することで そのケースだけに ブレークポイントを集中できます これで ブレークポイントは 条件が真のときにのみ停止します 他方 ログを使ってデバッグしたいけれど 停止は望ましくなく log文を挿入し 再ビルドして 解明したいと思う場合があります ブレークポイントエディタでは ブレークポイント到達時に実行する デバッガ式を追加することもできます print式を追加し ブレークポイントを設定して 自動的に続行します これで 再ビルドせずに 一時的なログを作成できます
デバッグシナリオの設定に 何分も費やした経験はないですか 1つのステップが大きすぎるだけで 設定を 全部やり直さなければならないことは? ログに使ったのと同じ デバッガコマンドを使用し プログラムが実行した内容を実行した理由を 確認する方法を紹介します 初めからやり直さなくても 根本原因に至ることができます 例えば このguard節を超えたら 関数を実行する想定だったのに 実行されず 理由も不明です 遡及して式を分解し 「p session」などコマンドによって デバッガで式の部分を評価することや guardの条件を評価することで 予期しない結果が返される原因を 特定できます デバッガは 先を予測するのにも使用できます ステップ実行の前にこれを実行して 未来を予測し ステップインやステップオーバーが 必要かどうかを判断できます 緑のプログラムカウンタを逆方向に ドラッグできることを 知っていましたか これにより 前の式の再実行が試行されます 副作用は巻き戻せないため プログラムはおかしな状態かもしれませんが クリックで停止して デバッグセッションを再開するのが 他の選択肢だとしたら どうでしょう これは大幅な時間短縮になります さらに 多数のブレークポイントを設定した状態で 問題をデバッグしている中で 中断せずに最初に戻りたい場合は デバッグバーのブレークポイントボタンで ブレークポイントを全部無効にして続行し 再度有効にして問題を再トリガします ときには 2回も3回も 同じデバッグをする必要があります 冗談のようですが 30回のときもあります プログラムのクラッシュ時は クラッシュの診断が行われるたびに アプリを再起動しなければなりません これは特に 変更すらしていないアプリを ビルドして実行するために 数秒余計に待たなければならない場合に もどかしく感じます command + control + Rで を実行すると ビルドステップ全体をスキップして 即座にデバッグに戻ることができます アプリの変更を開始しているが 古いコードを再度デバッグしたいと考えていて 前のセッションからビルドしていない場合も これを使用できます デバッグに集中しているときや 慣れないコードをデバッグしているときは すべきことを把握するのが 難しい場合があります Xcode 16では バックトレース全体をエディタで確認でき プロジェクト全体の関数がまとめられて 単一のエディタに表示されます これで 現在の場所に至った過程を 便利に概観できます この表示モードは デバッグバーの メモリデバッガとビューデバッガの コントロールの横で起動できます デバッグに「print」文を使っていますか とても便利なので私もよく使いますが 特に デバッグコンソールの出力を チーム全体で共有しなければならない場合に たちまち手に負えなくなります 私がprint文でマクロを使っていたことに 気づいたでしょうか 短縮ファイルパスを取得するfileIDや 現在地の関数の名前を取得するfunctionなど いくつかのマクロを使用できます その他のマクロについては ドキュメントをご覧ください これをきれいにしましょう print文は使用せず 「os_log」への切り替えを検討します これで デバッグレベルが 自分の設定したメッセージごとになります これらのマクロは不要になります 実行すると テキストを検索してフィルタしたり ライブラリからのメッセージのみ フィルタしたりできます メタデータを有効にして エラーや情報 デバッグといった種類や タイムスタンプとライブラリを表示できます ログメッセージに もうこれらのマクロが必要でないのは 移動のための矢印をクリックすることで ログメッセージの出所であるソースの行に 直接ジャンプできるからです これは print文ではできません デバッグの詳細については 本年の「Run, Break, Inspect」 セッションをご覧ください コンソールで実行できる便利な機能と os_logに付属する 各種メタデータの詳細については 「Debug with structured logging」を ご覧ください デバッガについて詳しくは 「Debug Swift debugging with LLDB」をご覧ください
バグを排除したところで 次はテストの話です 配布前にバグを拾うため テストは重要です バグを見つけたときは テストケースを追加して バグが再発しないようにします 特にコードベースが肥大化して複雑化すると 楽しい作業であるコードの記述を行う上で テストは非常に重要です プロジェクト内のテストを全部実行する場合 command + Uを使用します しかし 大抵は一度に1つのテストを すばやく繰り返します これを行うには そのテスト関数のひし形をクリックするか 階層の上のどこかをクリックして テストをまとめて実行します
以上は テストでできることの ほんの一部です テスト作業を効率的に行うための テクニックを さらにいくつか紹介します Xcode自体 優れたCIカバレッジを備えています プルリクエストはすべて Xcode Cloudを通じて実行されるため テストが統合前に合格することを 保証できます command + 6で テストナビゲータを起動すると すべてのテストが表示されます アプリの異なる部分について 複数のテスト計画がある場合 「含まれているテストのみ」に フィルタすることで 現在の計画のテストのみを表示できます テスト群のサイズによっては スクロールして適切なテストを実行するには これで十分かもしれません 私たちが作成するような よく記述された 優れたテストが大量にある場合は もっと的を絞る必要があるでしょう 関連するテストを タイトルで特定できる場合は テキストでフィルタできます Swiftテストでは タグでフィルタできます 適切なサブセットを特定したら それらを選択し コンテキストメニューを使って 特定のセットを実行します 実行後 これらのテストには ステータスが付きます 失敗に焦点を当てたい場合にも そのためのフィルタがあります テストは修正すると リストから自動的に消えます 便利で達成感があります アプリのデバッグと同様 30回のテスト というケースはよくあります 31回はさすがにないですが 少し前に元のテストメソッドから離れて アプリの核心部分について検索し スタックをデバッグするようになった 可能性があります テストを再度実行するために テストのひし形を探しに戻らなくても command + control + option + Gで いつでも前のテストを再実行できます 実行と同様に 問題について別の視点を得るためだけに コードを変更することなく デバッグセッションを再起動することも よくあります 「Test Without Building」または command + control + Uを使用できます 心安らぐ緑地のチェックマークと 悪気はないが不愉快な 赤地のバツ印の他にも Xcodeで表示されるテストステータスには いくつか種類があります 使い方を説明しましょう ときには テストを修正できないこともあります テスト駆動開発がお好きな方なら APIが機能する前に テストを記述しているかもしれません それらのテストは 想定どおりの失敗としてマークできます これらはバツ印付きの グレイのアイコンで表示されます ときどき バグの再発を招いてしまい 私のような プロジェクトマネージャーが止めても 少しの間 放置されることがあります この場合はスキップとしてマークできます 表示は矢印付きのグレイのアイコンになります まとまっているテストについては さまざまな結果が混ざっている場合は 集約ステータスのアイコンが表示されます すべてを緑に戻す準備ができたら これらのステータスに対して ナビゲータフィルタを使用し 適切なテストに的を絞り 前に説明したデバッグのテクニックを使用し 配布のための準備を万全にします テストを個別に実行する方法は すでにお見せしましたが テストは他にも多くの方法で実行できます 大抵は合格するのに たまに失敗するテストがある場合は 競合状態または 何らかの確定的でない動作が 発生している可能性が考えられます コンテキストメニューの を使いましょう テストを所定の回数実行したり 失敗するまで繰り返したりできます テストにログを追加することで 最終的に失敗したときに ログから理由を確認できます コマンドラインから 「xcodebuild test」で テストを実行できます スキーム テスト計画または個別のテストを 指定するだけで実行できます git bisectなどのツールと 併用すると効果的で バグが再発した タイミングを特定できます 継続的インテグレーション環境で テストを実行する準備ができ ワークロードをMac外に移すときは デベロッパアカウントに付属する Xcode Cloudの 1か月あたり25時間のコンピューティングを 無料で利用できます 特定のブランチにプッシュするとすぐに クラウドでのテストを開始する ワークフローを設定でき Xcode内で結果を確認して テストに合格したら TestFlightまたは App Store Connectに 直接送信するよう設定できます Xcode Cloudは 安全性と機密性にも優れています データは保存時に暗号化され アクセスは2ファクタ認証で保護されます ソースコードはビルド時にのみ使用され ビルド環境はビルドが完了すると すぐに破棄されます Xcode Cloudで作業を開始するには 「Create practical workflows in Xcode Cloud」をご覧ください 「Get the most out of Xcode Cloud」では より高度なヒントを紹介しています 優れたテストの書き方を学ぶには 「Author fast and reliable tests for Xcode Cloud」をご覧ください テスト計画では テストをグループ化して 望ましいときに 望ましいグループだけを実行します プロジェクトが拡大すると いくつかの異なるスキームでテストを実行したり テストを異なるグループにして 簡単なユニットテストを実行した上で コミット前にすべてをテストしたり することが必要になります そこで必要となるのがテスト計画です 各スキームには複数のテスト計画を設定でき テスト計画は複数のスキームにまたがります 新しいプロジェクトには 元から作成されたテスト計画があります まずは このテスト計画をの メニューから編集します 最初に 対象に含めるターゲットを選択します これは例えば ユニットテストやUIテストなどです 次に それらのターゲットから このテスト計画に含めるテストを選択します テスト計画を複数のスキームに 追加することもできます 最初にスキームを選択します 次にプラスボタンと をクリックします テスト計画は > で選択し > を選択または command + Uで実行できます コードカバレッジまたはテストカバレッジは テストの実行時に実行される コードベースの量を決定する方法です 問題を見つける上で テストを書くことは重要です そのため カバレッジを有効にして テストの効果を推定できるようにし 既存のテストが新しいコードを 対象に含んでいるかを確認します まず メニューから を有効にします 次に テストを実行します これは Xcodeが 実行範囲を特定する方法のため 実行して初めて結果が得られます テストを実行すると エディタの右側に数字が表示されます これはテスト中にコードブロックが 実行された回数です 0はコードが一度も実行されなかったことを 意味するので テストにギャップがあるか アプリでそのコードが まったく実行されない可能性があります このコードブロックは テスト中に5回実行されました command + 9で レポートナビゲータを使用して すべてのコードカバレッジの概要も 表示できます 現在設定されているコードカバレッジが ファイルごと また関数ごとに 表示されるため 改善に的を絞ることができます コードカバレッジを確認したタブは テストレポートと呼ばれます ここには 実行中のテストの状態や 失敗時に何が悪かったかについて 詳しいデータがあります 先ほど行ったテスト実行をクリックして テストされた内容の概要を見てみましょう 項目をクリックして テスト結果のみ確認することもできます このビューまたは概要ビューから 失敗したテストをダブルクリックして 何が起こったかを確認します 実行されたテストの 一連のイベントが 画面の録画と横並びで表示されます これは テスト中のアプリの状態を 確認するのに便利で 問題の原因を正確に特定できます 最下部のタイムラインでは エラーが発生した正確な時点を確認できます Developerアプリのテストについては 良いセッションが多数あります まずは「Testing your apps in Xcode」 ドキュメントをお読みください 次に 今年のセッション「Meet Swift Testing」 をご覧ください さて アプリの記述が完了し すべてのバグを取り除いて テストも全部済みました 次は 制作したアプリを 世界や 少なくともベータテスターに披露します 製品のリリースが間近に迫り 1.0ビルドを初めて使用するときが来ました TestFlightを使用して アプリをベータテスターに配信する方法 ビルド製品をアーカイブする方法 組み込みのXcode Organizerを使用して アプリについての詳細情報を得る方法を 紹介します アプリを一般公開する前に テストを次のレベルに進めて ベータテスターに実際に使用してもらい 意見を得たいものです どんな最善のテストでも 実際の使用に勝るものはありません
有料のデベロッパアカウントには TestFlightが含まれ 最大1万人のベータテスターに アプリを配信できます Eメールか ソーシャルメディアへの リンク公開による招待が可能です 新バージョンのアプリは自動的に ベータテスターのデバイスに展開されます また TestFlightは どのプラットフォームとも連動します 新規ビルドを公開すると 注目すべき点がテスターにわかるよう TestFlightにリリースノートが追加されます これでテスターから意見と分析が得られます 今説明した機能はすべて Xcodeに組み込まれています TestFlightまたはApp Storeへの アプリの公開はアーカイブから始まります アーカイブは コンパイル済みアプリのスナップショットで リリースビルドが含まれています このリリースバージョンは 容量を節約するよう 最適化されていて 問題の調査に必要なデバッグ情報は もはや含まれていません このアーカイブには デバッグシンボルも含まれているため 保存しておいて後でデバッグできます 選択した配信先向けに コンテンツを再パッケージ化して アプリを配信することもできます
ビルドを配布する用意が整ったら メニューで を選択します アプリがXcodeによって もう一度ビルドされてからバンドルされ 結果がOrganizerに表示されます 良好な動作状態に至ったら 変更をコミットするだけでなく アーカイブを作成しましょう アプリの動作が維持され デバイスへのインストールや 配信が簡単になります それには アーカイブを選択して ボタンをクリックします アプリを配信するためのプリセットが いくつか表示されます オプションでは アプリを TestFlightかApp Store Connectに アップロードします は App Reviewをスキップします 保護機能により App Storeへの誤送信を防ぎます これはコンテンツプロバイダ/組織の ベータテスターのみが使用でき 外部のテスターは使用できません そして の各オプションは ポータルに登録されたデバイスに ユーザーがインストールできるよう 最適化されたビルドを生成します Xcode Cloudは TestFlightとも統合します ワークフローを設定しておけば ビルドが成功してテストに合格すると TestFlightに直接送信されて テスターは最新のビルドを取得できます Gitコミットメッセージからプルして テスターノートを自動化するスクリプトを 設定することもできます TestFlightの使用方法については Tech Talksのビデオ「Get started with TestFlight」をご覧ください テスターリリースノートの自動化については 記事「Including notes for testers with a beta release of your app」をお読みください Xcode Cloudの力を引き出すには 昨年の「Simplify distribution in Xcode and Xcode Cloud」をご覧ください ビルドがTestFlightに送信され テスターが最新のベータ版を実行しており ユーザーが最新のリリース版を 取得したところで Xcode Organizerを詳しく見てみましょう command + option + shift + O で起動します Organizerでは Xcodeで直接 豊富な分析にアクセスでき ユーザーのプライバシーは守られます ここにレポートされるのは 皆さんのような サードパーティデベロッパへの 意見や診断の共有に同意した ユーザーのみですが ユーザーの代表的な サンプルと考えられます TestFlightまたはApp Storeへの配布後 このウィンドウで次に確認できるのは 編集 デバッグ テスト コミットを 行うべき対象です この繰り返し作業がソフトウェアエンジニア としての私たちの仕事であり 顧客のアプリ体験が 最善のものになるようにします また プロジェクトマネージャーも 仕事が途切れません 追跡すべき機能や修正すべきバグ 解決すべき問題が 尽きることはないからです まずはタブを見て 自分たちが次に提供すべき 優れた機能を見つけましょう 機能開発は取り組んでいて 最も楽しいものです TestFlightのベータテスターは ここで意見を共有できます 私たちはユーザーの意見を聞きたいと 思っています これらの機能のうちいくつかは すぐに着手すべきだと思いますので 次のスプリントに加えましょう しかし ここで私の中の プロジェクトマネージャーが顔を出し まずは品質の問題を解決すべきだと 主張します 起動オーガナイザを見ると リリース済みのバージョンのアプリが 起動に時間がかかっていることがわかります 本番環境に急いで移行したためか アプリ起動時にデータをクラウドで同期する というこの機能は もっと時間をかければより効率的に 記述できたかもしれません そして 最新のベータ版では 停止数が大幅に急増しています まずはこれらの問題を解決するために これらの機能は将来のスプリントに 先送りしなければならないでしょう このデータを見るときに 皆さんとユーザーでは環境が異なる 場合があることを忘れないでください おそらく皆さんのデバイスのOSは最新版ですが ユーザーは違うかもしれません 現実にはネットワーク可用性の問題が あるかもしれませんが 机上のテストではわかりません これが アプリの動作について より多くのデータを ベータ版プログラムで収集する理由です デベロッパ プロジェクトマネージャー または製品マーケティングパートナーは こうした様々な情報すべてに Xcode内で直接無料でアクセスして 製品の目標の推進に 役立てることができます 本日は ナビゲーションの詳細 迅速な編集のコツ コードの整理について 多くの詳しい内容を学習しました ややこしい状況をデバッグするために ブレークポイントを使用するヒントと コンソールを使用して 自身で先を予測する方法を紹介しました 配布前にテストでバグを検出する方法を 確認しました これらのテストでは テストレポートに テストの実行内容の履歴が表示されます 次に TestFlightによるベータテスターへの アプリ配信について説明し Organizerでの ユーザーの意見の見方を説明しました
最適化のポイントは 編集 デバッグ テスト コミットのワークフローです ご視聴ありがとうございました さあ 皆でバグの修正に取り掛かりましょう
-
-
10:26 - Warning and error annotations
#warning("This is a warning annotation") #error("This is an error annotation")
-
10:58 - Mark comments
// MARK: This is a section title
-
14:09 - Placeholder
<#placeholder#>
-
17:30 - showStarView()
showStarView()
-
17:51 - Breakpoint #1
let task = URLSession.shared.dataTask(with: cloudURL, completionHandler: handleUpdatesFromCloud)
-
17:53 - Breakpoint #2
videos = loadVideosFromCloud()
-
18:17 - Swift error breakpoint
let url = try! getVideoResourceFilePath()
-
18:34 - Swift error throw
throw URLLoadError.fileNotFound
-
18:59 - Conditional breakpoint
cloudURL.scheme == "https"
-
19:18 - Print statement in conditional breakpoint
p "Username is \(cloudURL.user())"
-
19:44 - guard clause
guard cloudURLs.allSatisfy({ $0. scheme == "https" }), session.configuration.networkServiceType == .video else { return }
-
19:56 - p session
p session
-
19:58 - p first part of guard clause
cloudURLs.allSatisfy({ $0. scheme == "https" })
-
20:02 - p second part of guard clause
p session.configuration.networkServiceType == .video
-
20:11 - Random star rating
var starRating: Int { let randomStarRating = Int.random(n: 1..<5) return randomStarRating }
-
21:16 - Converting starRatingPercentage to Int
var starRating: Int { return Int((starRatingPercentage * 5).rounded()) }
-
21:46 - print statements for debugging
var releaseDate: Date { print("🎬 Entering func \(#function) in \(#fileID)...") let currentDate = Date() let gregorianCal = Calendar(identifier: .gregorian) var components = DateComponents() components.year = releaseYear print("\(#fileID)@\(#line) \(#function): 📅 releaseYear is \(releaseYear)") if releaseYear == gregorianCal.component(.year, from: currentDate) { components.month = Int(releaseMonth) isNewRelease = true print("\(#fileID)@\(#line) \(#function): 🆕 this is a new release!") } if releaseYear < 2000 { isClassicMovie = true print("\(#fileID)@\(#line) \(#function): 🎻 this one is a classic!") } let calendar = Calendar(identifier: .gregorian) return calendar.date(from: components)! }
-
22:09 - os_log statements for debugging
var releaseDate: Date { os_log(.debug, "🎬 Entering func \(#function) in \(#file)...") let currentDate = Date() let gregorianCal = Calendar(identifier: .gregorian) var components = DateComponents() components.year = releaseYear os_log(.info, "📅 releaseYear is \(releaseYear)") if releaseYear == gregorianCal.component(.year, from: currentDate) { components.month = Int(releaseMonth) isNewRelease = true os_log(.info, "🆕 this is a new release!") } if releaseYear < 2000 { isClassicMovie = true os_log(.info, "🎻 this one is a classic!") } let calendar = Calendar(identifier: .gregorian) return calendar.date(from: components)! }
-
23:19 - Sample unit tests
import Testing @testable import Destination_Video struct DestinationVideo_UnitTests { private var library = VideoLibrary() // Make sure starRating is returning a percentage @Test func testStarRating() async throws { for video in library.videos { #expect(video.info.starRating > 0) #expect(video.info.starRating <= 5) } } // Make sure the library loads data from the json file @Test func testLibraryLoaded() async throws { #expect(library.videos.count > 1) } }
-
24:15 - Sample UI tests
import XCTest final class Destination_VideoUITests: XCTestCase { private var app: XCUIApplication! @MainActor override func setUpWithError() throws { // UI tests must launch the application that they test. app = XCUIApplication() app.launch() // In UI tests it is usually best to stop immediately when a failure occurs. continueAfterFailure = false } @MainActor func testABeach() throws { // Tap the button to load the detail view for the "A Beach" video let aBeachButton = app.buttons["A Beach"].firstMatch aBeachButton.tap() // Make sure it has a Play Video button after going to that view let playButton = app.buttons["Play Video"] XCTAssert(playButton.exists) // Make sure the star rating for this video contains 4 stars to avoid issue we saw previously where it was only a single star because starRating was incorrectly a percentage instead of an Int let theRatingView = app.staticTexts["TheRating"] XCTAssert(theRatingView.label.contains("⭐️⭐️⭐️⭐️⭐️")) } @MainActor func testMainView() throws { // We should have at least 10 buttons for the various videos let buttons = app.buttons XCTAssert(buttons.count >= 10) // Check that the most popular videos have buttons for them for expectedVideo in ["By the Lake", "Camping in the Woods", "Ocean Breeze"] { XCTAssert(app.buttons[expectedVideo].exists) } } @MainActor func testLaunchPerformance() throws { if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { // This measures how long it takes to launch your application. measure(metrics: [XCTApplicationLaunchMetric()]) { XCUIApplication().launch() } } } }
-
24:19 - Swift Testing tags
@Test(.tags(.stars)) func testStarRating() async throws { for video in library.videos { #expect(video.info.starRating > 0) #expect(video.info.starRating <= 5) } } @Test(.tags(.library)) func testLibraryLoaded() async throws { #expect(library.videos.count > 1) } extension Tag { @Tag static var stars: Tag @Tag static var library: Tag }
-
26:35 - Running xcodebuild test from the command line
xcodebuild test -scheme DestinationVideo xcodebuild test -scheme DestinationVideo -testPlan TestAllTheThings xcodebuild test -scheme DestinationVideo -testPlan TestAllTheThings -only-testing "Destination VideoUITests/testABeach"
-
29:03 - Missing Code Coverage
func toggleUpNextState(for video: Video) { if !upNext.contains(video) { // Insert the video at the beginning of the list. upNext.insert(video, at: 0) } else { // Remove the entry with the matching identifier. upNext.removeAll(where: { $0.id == video.id }) } // Persist the Up Next state to disk. saveUpNext() }
-
29:19 - Code Coverage executed 5 times
init() { // Load all videos available in the library. videos = loadVideos() // The first time the app launches, set the last three videos as the default Up Next items. upNext = loadUpNextVideos(default: Array(videos.suffix(3))) }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。