iOS開発のデバッグツールchiselの紹介

先日の<a href="http://atnd.org/events/49477">yidev@恵比寿勉強会</a>参加させて頂き、その際の@dealforestさんの発表で<a href="https://github.com/facebook/chisel">facebook/chisel</a>というツールを知りました。

これがなかなか便利そうなので、紹介します。

@dealforest さんのblogエントリ
<a href="http://blog.dealforest.net/2014/04/presente_chisel_in_yidev_ebisu/"> yidev@恵比寿勉強会 で chisel について発表してきた (動画付き)</a>

chiselは、LLDBのコマンドラインからpythosスクリプトでlldbの機能をラップして便利に使うコマンド群のようです。

そもそも私はLLDBをまったく使ってきませんでしたが（汗）、これでNSLog差し込みが減って楽になりそうです。

# インストール

1. brew install chisel でインストール

2. ~/.lldbinit-Xcodeに、以下を記載（fblldb.pyのパスは環境に合わせて記載してください。）

```bash:~/.lldbinit-Xcode
command script import /usr/local/Cellar/chisel/1.1.0/libexec/fblldb.py
```

(.lldbinit だと、Xcodeから起動したLLDBでは呼ばれないので注意。)

Xcodeのlldbプロンプトで、helpとたたくと、chiselで使えるコマンド群が表示されます。さらにhelp &lt;command&gt; で、コマンドの詳細説明が出力されます。

```objectivec:lldb
(lldb) help
The following is a list of built-in, permanent debugger commands:
〜略〜
pca -- Run Python function __FBPrintCommands_pca
pcells -- Run Python function __FBPrintCommands_pcells
pclass -- Run Python function __FBPrintCommands_pclass
pinternals -- Run Python function __FBPrintCommands_pinternals
pinvocation -- Run Python function __FBInvocationCommands_pinvocation
pivar -- Run Python function __FBPrintCommands_pivar
presponder -- Run Python function __FBPrintCommands_presponder
ptv -- Run Python function __FBPrintCommands_ptv
pvc -- Run Python function __FBPrintCommands_pvc
pviews -- Run Python function __FBPrintCommands_pviews
show -- Run Python function __FBDisplayCommands_show
taplog -- Run Python function __FBFindCommands_taplog
unborder -- Run Python function __FBDisplayCommands_unborder
unmask -- Run Python function __FBDisplayCommands_unmask
visualize -- Run Python function __FBVisualizationCommands_visualize
vs -- Run Python function __FBFlickerCommands_vs
wivar -- Run Python function __FBDebugCommands_wivarFor more information on any particular command, try 'help '.
(lldb) help pvc
Print the recursion description of <aViewController>.

Arguments:
  <aViewController>; Type: UIViewController*; The view controller to print the description of.

Syntax: pvc <aViewController>

This command is implemented as FBPrintViewControllerHierarchyCommand in /usr/local/Cellar/chisel/1.1.0/libexec/commands/FBPrintCommands.py.

(LLDB adds the next line, sorry...)
Syntax: pvc
(lldb)
```

# 便利なコマンドたち
##pvc
ViewControllerの階層構造を表示してくれます。
pvc &lt;viewController&gt; で、指定したViewController配下の階層構造を表示します。

```
(lldb) pvc
 <UINavigationController: 0x109268650; view = <UILayoutContainerView; 0x109419100>; frame = (0, 0; 320, 568)>
 | <KJMasterViewController: 0x109410ec0; view = <UITableView; 0x10a82fc00>; frame = (0, 0; 320, 568)>

(lldb) pvc 0x109410ec0
 <KJMasterViewController: 0x109410ec0; view = <UITableView; 0x10a82fc00>; frame = (0, 0; 320, 568)>
 pviews
 <UIWindow: 0x109319480; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x109319d80>; layer = <UIWindowLayer: 0x109318560>>
 | <UILayoutContainerView: 0x109419100; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x10931bfa0>; layer = <CALayer: 0x109419320>>
 | | <UINavigationTransitionView: 0x10931b970; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x109259740>>
 | | | <UIViewControllerWrapperView: 0x109527b30; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x109530800>>
 | | | | <UITableView: 0x10a82fc00; frame = (0 0; 320 568); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x109266c80>; layer = <CALayer: 0x1095310c0>; contentOffset: {0, -64}>
 〜略〜
```

## pviews
viewの階層構造を表示してくれます。引数でviewを指定すると、指定したview配下の階層構造が表示されます。

```
(lldb) pviews
<UIWindow: 0x109319480; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x109319d80>; layer = <UIWindowLayer: 0x109318560>>
| <UILayoutContainerView: 0x109419100; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x10931bfa0>; layer = <CALayer: 0x109419320>>
|    | <UINavigationTransitionView: 0x10931b970; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x109259740>>
|    |    | <UIViewControllerWrapperView: 0x109527b30; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x109530800>>
|    |    |    | <UITableView: 0x10a82fc00; frame = (0 0; 320 568); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x109266c80>; layer = <CALayer: 0x1095310c0>; contentOffset: {0, -64}>
〜略〜
```

## pcells
tableViewで表示されているセルの一覧を表示

## presponder
指定したクラスのレスポンダーチェインを表示

```
(lldb) pcells
 <__NSArrayI 0x109422590>(
 <UITableViewCell: 0x10928e800; frame = (0 0; 320 44); text = '2014-04-27 14:13:37 +0000'; autoresize = W; layer = <CALayer: 0x10928b300>>,
 <UITableViewCell: 0x10933ada0; frame = (0 44; 320 44); text = '2014-04-27 14:13:35 +0000'; autoresize = W; layer = <CALayer: 0x10933b090>>,
 <UITableViewCell: 0x10932fd10; frame = (0 88; 320 44); text = '2014-04-27 14:12:38 +0000'; autoresize = W; layer = <CALayer: 0x109322c00>>,
 <UITableViewCell: 0x109273a10; frame = (0 132; 320 44); text = '2014-04-27 14:11:32 +0000'; autoresize = W; layer = <CALayer: 0x10925d540>>
 )

(lldb) presponder 0x10933ada0
 <UITableViewCell: 0x10933ada0; frame = (0 44; 320 44); text = '2014-04-27 14:13:35 +0000'; autoresize = W; layer = <CALayer: 0x10933b090>>
 | <UITableViewWrapperView: 0x10926ae50; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x10926b050>>
 | | <UITableView: 0x10a82fc00; frame = (0 0; 320 568); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x109266c80>; layer = <CALayer: 0x1095310c0>; contentOffset: {0, -64}>
 | | | <KJMasterViewController: 0x109410ec0>
 | | | | <UIViewControllerWrapperView: 0x109527b30; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x109530800>>
 | | | | | <UINavigationTransitionView: 0x10931b970; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x109259740>>
 | | | | | | <UILayoutContainerView: 0x109419100; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x10931bfa0>; layer = <CALayer: 0x109419320>>
 | | | | | | | <UINavigationController: 0x109268650>
 | | | | | | | | <UIWindow: 0x109319480; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x109319d80>; layer = <UIWindowLayer: 0x109318560>>
 | | | | | | | | | <UIApplication: 0x109308360>
 | | | | | | | | | | <KJAppDelegate: 0x10921a1e0>
```

また、対象のviewをアプリ上でインタラクティブに特定するための以下のようなコマンドも用意されています。
## taplog
実行すると、フォーカスがアプリ（シミュレータor実機)に戻り、画面をtapすると、tapしたviewの情報が表示される。
## vs
インタラクティブに、viewの選択/サーチができる。実行すると、指定したViewが点灯表示され、以下のキー入力（＋リターン）で、対象viewが遷移します。

```
(w) superviewへ移動
(s) 最初のsubviewへ移動
(a) 同階層の一つ前のviewへ移動
(d) 同階層の次のviewへ移動
(p) 階層を表示
(q) 終了
```

## pclass
指定したクラスの継承を表示

## fv
viewクラス名の正規表現引数指定すると、該当するviewを表示。

## fvc
viewControllerクラス名の正規表現引数指定すると、該当するviewControllerを表示。

## 最後に

コレ以外にも、指定したViewをアプリ上でマーキングしたり、指定したViewをマーキングしたり非表示にしたり、osx上にイメージ出力したりと、色々と便利な機能が用意されているので、試してみてはいかがでしょうか。

@takayamaさんyidev運営ごくろうさまでした。