EDIT MODE

モバイルアプリ開発に関することを書いています

"WebエンジニアのためのiOSデバッグ速習会"で学んだことのまとめ

WebエンジニアのためのiOSデバッグ速習会@Wantedly に参加してきたので、内容を忘れないようまとめました。

wantedly.connpass.com

参加者は事前に Xcode を自分の PC にインストールしておき、講師の人が説明した後に実際に手を動かして確認していく、というスタイルでした。

また速習会中は、Sync を使って参加者同士がコミュニケーションを取るというのは、独特で面白かったです。

講師は @hedjirog さんでした。

やったこと

講師の方が資料を用意してくださったので、それに沿って以下のようなことをやりました。

テーマは iOS アプリのデバッグです。 使用したのは Xcode 7.1.1 です。

  1. 題材アプリ Artsy のインストール
  2. ブレークポイントを配置して任意のコードで実行を止める
  3. ビューデバッガでビュー構造からクラスなどを特定する
  4. chisel を使って LLDB コマンドでデバッグする
  5. ExceptionBreakpoint でアプリのクラッシュをデバッグする

おまけ: PonyDebugger を利用して通信内容を確認する

題材アプリ Artsy のインストール

デバッグ対象とするアプリは OSS で公開されている Artsy を使いました。 README にも書かれている通り、以下の手順でインストールできます。(結構時間かかります。)

git clone https://github.com/artsy/eigen.git
cd eigen
bundle install
make oss
bundle exec pod install
open Artsy.xcworkspace

注意点として普段 Ruby を使っていない PC だと、bundler がインストールされていないかもしれません。 そのときは、以下のコマンドでインストールされているか確認し、

gem contents bundler

見つからなければ、以下のコマンドでインストールします。

gem install bundler

パーミッションで怒られたら管理者権限で実行します。

sudo gem install bundler

Breakpoint を配置して任意のコードで実行を止める

普段何かしらの IDE を使っていれば、おなじみのデバッグ方法ですね。

Breakpoin の配置は、行番号のあたりをクリックするだけです。セットした Breakpoint は、左側の Breakpoint Navigator にリスト化されていきます。

f:id:androhi:20151127170505p:plain

さらに Xcode の場合は、セットした Breakpoint に任意のコマンド実行などを追加出来るとのこと。

これを使えば Breakpoint に到達したときに、音を鳴らすとかも簡単に出来るようです。

f:id:androhi:20151127170537p:plain

Breakpoint の削除は、Breakpoint をドラッグして離せば消えます。

ビューデバッガでビュー構造からクラスなどを特定する

ビューデバッグを開始(アプリ実行中にカルーセルみたいなボタンをクリック)すると、IDE 内にビュー構造を表したオブジェクトが立体表示出来ます。 (iOS エンジニアの人に聞いたら、割りと最近追加されたものらしいです。)

f:id:androhi:20151127170818p:plain

f:id:androhi:20151127170608p:plain

UI をクリックすると、その UI が何のクラスなのか分かります。そして、右側にはそのコンポーネントの詳細な情報が、確認出来るようになっています。

f:id:androhi:20151127170801p:plain

似たもので Reveal という、有償のビュー構造解析ツールがあるようです。(そっくりですね。こっちの方がサクサク動くらしい。)

AndroidStudio にも、この機能欲しいですね。

chisel を使って LLDB コマンドでデバッグする

chisel というデバッグツールがあるとのことです。 facebook 社が OSS として公開しています。

Chisel is a collection of LLDB commands to assist debugging iOS apps.

これを活用したデバッグ方法です。(*1

chisel は Homebrew でインストールできます。

brew update
brew install chisel

chisel を使うには、設定ファイルが必要です。ホームディレクトリ下に、 .lldbinit というファイルが無ければ作成します。 .lldbinit ファイルには、以下を記述しておきます。

command script import /path/to/fblldb.py

/path/to の部分は環境によって変わります。自分の環境下でのパスを確認するには、以下で出力されます。

brew info chisel

chisel を使う手順は、アプリを実行したら || ボタンで止めて、コンソールでコマンドを実行します。 コマンドの説明は chisel の README に載ってます。

今回試したのは、以下のコマンドです。

pviews

コマンドを叩くと、以下の様なテキストベースのビュー構造を返してくれます。 (長いので途中省略しています。)

<ARWindow: 0x7fdf40c1e960; baseClass = UIWindow; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fdf40c20e30>; layer = <UIWindowLayer: 0x7fdf40c1c760>>
   | ARTopMenuViewController:0x7fdf40d17cb0 1c.[ARNavigationController 0x7fdf41890000: ] <UIView: 0x7fdf40e3af30; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fdf40cc4ae0>; layer = <CALayer: 0x7fdf40e78c70>>
   |    | <UIView: 0x7fdf40ebb230; frame = (0 621; 375 46); layer = <CALayer: 0x7fdf40ebb3a0>>
   |    |    | <ARNavigationTabButton: 0x7fdf40eaed20; baseClass = UIButton; frame = (0 0.5; 46 45.5); opaque = NO; layer = <CALayer: 0x7fdf40ea9e30>>
   ...
   |    |    |    |    | <UIImageView: 0x7fdf40c1f910; frame = (10 10; 20 20); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fdf40c55750>>
   |    |    |    |    | XX (<UIButtonLabel: 0x7fdf40d1f100; frame = (20 10.5; 0 19); hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fdf40d10790>>)
   |    | XX (<NPKeyboardLayoutGuide: 0x7fdf40ec8e90; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x7fdf40ec7a60>>)

f:id:androhi:20151127170939p:plain

taplog

コマンドを叩くと、シミュレーター(もしくは実機)がアクティブになります。

この状態でアプリ上のどこかをタップすると、そのイベントの開始位置で再び止まり、エディタには該当のコードを表示してくれます。

f:id:androhi:20151127170956p:plain

border

コマンドの後に、UI コンポーネントのアドレスを渡してあげると、シミュレーター(もしくは実機)の該当する UI 部分が赤枠で囲われます。

f:id:androhi:20151127171016p:plain

ExceptionBreakpoint でアプリのクラッシュをデバッグする

アプリがクラッシュしたときに、以下のように通常コンソールに出力される情報だけでは、発生元を特定するのが大変です。

f:id:androhi:20151127171042p:plain

そういうときは ExceptionBreakpoint を使うと、例外が発生した箇所で実行を止めてくれるとのことです。

使い方は、左側の Breakpoint Navigator に切り替え、アプリを実行させます。 その状態で、左下のプラスボタンから「Add Exception Breakpoint...」をクリックし、ExceptionBreakpoint を設定します。

f:id:androhi:20151127171101p:plain

実際にクラッシュを起こすと、以下のように例外が発生した場所のコードが表示され、そこで実行が止まります。

f:id:androhi:20151127171115p:plain

PonyDebuggerを利用して通信内容を確認する

Square 社が OSS で公開している PonyDebugger という、iOS 用の通信デバッグツールとのことです。

Remote network and data debugging for your native iOS app using Chrome Developer Tools

これは時間が足りず試せませんでした。 GitHub の README を見れば分かりますが、ブラウザで通信のリクエストやレスポンスが確認出来るようです。 数行アプリにもコードを書かないと行けないので、導入するときは一手間必要そうですね。

(ただ Android アプリ開発も行う人とかは特に、charles とか wireshark とかのツールで、両方ともカバーした方が便利かなと思いました。)

まとめ

  • 特定のコードでアプリを止めたい時は Breakpoint を設定する
  • Breakpoint はアクションを追加できるので必要に応じて活用する
  • UI まわりはビューデバッガを使うと便利
  • より細かいデバッグには chisel を活用すると便利
  • クラッシュ発生源の特定には ExceptionBreakpoint を使う

個人的な感想として僕は普段 Android アプリの開発がメインで、IDE は AndroidStudio を使うことが多いのですが、View まわりのデバッグXcode の方が良く出来てるなと感じました。

余談

懇親会中 wantedly 社の方にオフィスを案内してもらったのですが、とにかくお洒落すぎて素敵なオフィスでした。会議室の名前が全部ジョジョのスタンド名で、とにかくかっこいいです。

それとこちらで販売してる wantedly パーカーいいですねっていう話しになったのですが、高いだけあって物がいいらしいので気になってきました。

*1:なお chisel については、こちらのブログが詳しいようです。 yidev@恵比寿勉強会 で chisel について発表してきた (動画付き)