Apple Watch アプリと同時に親アプリもデバッグする

Apple Watch アプリプログラミング

Apple Watch アプリをデバッグするとき、Apple Watch を制御する Extension が親の iPhone アプリとは別プロセスで起動するため、そのままでは Extension だけしかブレークポイントで止められません。

それだと Apple Watch と親の iPhone アプリとを連携するコードをデバッグしにくいので、親の iPhone アプリでもブレークポイントで停止できるようにしてみました。


Apple Watch アプリは、その親になる iPhone アプリと連携して処理を進めることもできます。

ただし、Apple Watch を制御する WatchKit Extension とその親の iPhone アプリとは別プロセスで動作するため、Xcode のデバッグモードで実行したとき、そのままだと WatchKit Extension 側のコードに貼ったブレークポイントでしか止まってくれません。

そこで、親の iPhone アプリを実行しているプロセスにも Xcode のデバッガをアタッチすることで、どちらのプロセスでもブレークポイントが機能するようにしてみました。

親の iPhone プロセスにデバッガをアタッチする

まず、Xcode で普段どおりに Apple Watch アプリのデバッグを開始します。

そうして Apple Watch アプリと iOS シミュレーターが起動したら、Xcode のメニューから Debug Attach to Process を選択すると、アタッチできるプロセスが一覧で表示されます。

ここのLikely Targets に分類されている中から、親アプリとして使う通常の iPhone アプリを(WatchKit App ではない方を)選択します。

これで、親のアプリにもデバッガをアタッチできました。


こうすることで WatchKit Extension で使うコードに設定したブレークポイントだけでなく、その親アプリとして使うコードに設定したブレークポイントも正しく動作するようになりました。

親アプリのプロセスにアタッチしたときの様子

親の iPhone アプリのプロセスにデバッガをアタッチすると、Xcode の停止ボタンを長押ししたときに表示される停止候補の一覧に、アタッチした親アプリのプロセスも表示されるようになります。

ログナビゲーターを確認すると、たとえば通常どおりにデバッグを開始しただけでも WatchKit Extension と親の iPhone アプリの両方が Debug 実行中として表示されていましたが、

デバッガを手動でアタッチすると、それに加えてもう一つ、親の iPhone アプリがデバッグ状態になっているのが分かります。

この、新しく追加されたデバッグプロセスのブレークポイントも、WatchKit Extension のブレークポイントと併せて捕捉できるようになります。

ブレークポイントで中断した後に先へ進める操作はもちろん、その瞬間の変数の内容を変数ビューで確認することもできるので、親の iPhone アプリと連携して動作する Apple Watch アプリのデバッグがしやすくなります。

コンソールに出力される内容

ところで、デバッグをしているときによく使うのがNSLog などを使って状況をコンソールに出力する手法ですが、この手法を親の iPhone アプリで使用しても、その内容は Xcode のコンソールログには出力されません。

これは今回のデバッガをアタッチする方法に限らず、通常のデバッグ方法でも、親アプリの NSLog で出力した内容は Xcode のコンソールログでは確認できません。


ただしブレークポイントで出力するログメッセージであれば、Xcode でアタッチしているプロセスのものは Xcode のコンソールログに出力されます。

ログを表示したいところにブレークポイントを設置して、Log Message アクションを設定します。

このとき、オプションのAutomatically continue after evaluating actions にチェックを入れておくことで、このブレークポイントで停止することなく、ログメッセージだけが表示されて次のステップへ進んでくれます。


こうして出力したデバッグメッセージは、それぞれ別々のデバッグログに表示されます。

確認したい方のログにログナビゲーターで切り替える必要がありますが、ログナビゲーターには 8 で即座に移動できて、その後にキーキー でログを切り替えられるので、操作に慣れればそれほど苦にはならなそうです。

ブレークポイントでログメッセージを表示する方法など、さまざまな使い方は 書籍『Xcode 5 徹底解説 で紹介しています。また、@@dealforestさん が作成した Xcode プラグイン『Tuna 』を使うと、変数の内容をブレークポイントのログメッセージで簡単に出力できて便利です。

NSLog で出力したメッセージはシステムログで確認できる

ところで、NSLog を使ってメッセージを出力すると、その内容はシステムログから確認できます。

まず、WatchKit Extension のコードから NSLog を使ったときには、その内容を Xcode のデバッグコンソールで普通に確認できます。そしてその親の iPhone アプリのコードから NSLog を使ったときは、その内容は iOS シミュレータのシステムログで確認できます。


iOS シミュレータのシステムログを表示するには、iOS シミュレータのメニューから Debug Open System Log... を選択します。

そうするとシステムログのウィンドウが表示され、そこに iOS シミュレータのコンソールログが表示されます。

ここには WatchKit Extension で出力した NSLog の内容と、その親の iPhone アプリで出力した NSLog の内容の両方が表示されます。それと合わせて、この iOS シミュレータ上で出力された全てのログが表示されるので、かなり雑多な感じになっています。

ただ、ツールバーにあるマーカーを挿入 機能で目標を入れたり、右上の検索フィールドを使ってアプリ名などで表示するログを絞り込めたりするので、このあたりの機能を上手に使えばログを追いやすくなります。

iOS シミュレータのコンソールログのウィンドウは、iOS シミュレータをアクティブにした状態で / を押すとすぐに表示できます。

親のアプリをデバッガにアタッチするときの注意点

デバッガをアタッチすることで親の iPhone アプリでもブレークポイントを使えて便利なのですが、注意しないといけない煩わしい面も存在しています。


親の iPhone アプリにデバッガをアタッチしたとき、次に Apple Watch アプリのデバッグを再実行しようとすると、次のようなエラーメッセージが 6 個くらい画面に表示されてしまい、デバッグを進められない様子でした。

このメッセージが表示されないようにするには、デバッグを再実行するためには、実行中のデバッグプロセスを全て停止させてから、デバッグを開始しないといけないようです。

それには、Xcode の停止ボタンを押せるだけ押す必要があるようでした。

起動しているデバッグプロセスの数だけ停止ボタンを押せるので、そうやってデバッグプロセスを全て停止してあげれば、再び実行ボタンを押したときには普通に Apple Watch アプリのデバッグを始められるようになります。

Xcode の停止ボタンは . でも押したことにできるので、これを使うとずいぶん楽に押せるようになります。ただ、ときどきまだデバッグプロセスが残っているのに、このショートカットキーを押しても停止できないことがあるのが厄介です。その場合でも Xcode のツールバーから停止ボタンをクリックすれば、残りのデバッグプロセスを終了できる様子でした。

親アプリのデバッグを快適に進めるための課題

上記のデバッグを再び始めるときにデバッグプロセスの停止が必要になる点もそうですし、デバッグを再び始めたときに親アプリへデバッガをその都度アタッチしないといけないのも少し面倒です。

この、デバッガのアタッチとデバッグプロセスの終了(デタッチ)操作をなんらかの方法で自動化で出来ればずいぶん勝手が良くなるでしょうから、自動化が実現可能かそのうち調べてみたいところです。


ただ、今のところは必要な都度、手動で操作する必要があります。

準備が面倒なので毎回使う訳にも行かなそうですけど、それでも動作を検証する方法は、今回お話したデバッガをアタッチする方法に加えて、上記でも少し紹介したシステムログを使って iOS シミュレータのログを見る方法、そして本来の XCTest を使った iOS アプリで使う機能のテストなどがあります。

これらを上手く組み合わせれば、WatchKit Extension とその親アプリとで連携するコードのテストもだいぶしやすくなりそうです。