モチベーション
『画面遷移ごとに表示中のビューコントローラのクラス名を確認したい』
画面構成とビューコントローラクラス名の関係を把握していない場合など、
上記のような場面に遭遇することがあります。
各ビューコントローラクラスにログ出力処理を仕込んだり、
その後、不要になったログ出力処理を削除するのは面倒です。
このような問題を解決する方法として、
Symbolic Breakpoint を利用した方法を紹介したいと思います。
Symbolic Breakpoint
Symbolic Breakpoint とは特定のメソッドが呼び出されたときブレークさせるためのブレークポイントです。
ブレークポイントを追加する
Breakpoint navigator を表示して、 Symbolic Breakpoint... から追加します。
次に、追加されたブレークポイントをダブルクリックして Symbol を指定します。
例えば、Symbol として -[UIViewController viewDidLoad]
を指定した場合は、
全ての UIViewController の viewDidLoad でブレークさせることができます。
$arg1, $arg2, $arg3
Symbolic Breakpoint でブレークすると次のオブジェクトを参照することができます。
変数 | 意味 |
---|---|
$arg1 | メッセージのレシーバ |
$arg2 | メッセージ |
$arg3 | メッセージの引数 |
例えば、Symbol として -[UIViewController viewDidLoad]
を指定した場合は
$arg1
には UIViewController のオブジェクト、 $arg2
には viewDidLoad が設定されます。
viewDidLoad は引数を取らないので $arg3
は nil
です。
Symbolic Breakpoint でブレークした際に、
lldb でオブジェクトの description を表示する場合は次のように操作します。
(lldb) po $arg1
<<クラス名>: アドレス>
(lldb) po (SEL)$arg2
"viewDidLoad"
(lldb) po $arg3
<nil>
ブレークポイント通過時に LLDB コマンドを実行する
ブレークポイントで停止させずに自動で通過させて、通過したタイミングで LLDB コマンドを自動で実行させることもできます。
Automatically continue after evaluating actions にチェックを入れて、
add action で po $arg1
を設定します。
これでブレークポイントで停止せずに、通過したタイミングで po $arg1
が実行されます。
画面遷移のタイミングでクラス名を表示させる
それでは本題です。
Symbol に -[UIViewController viewDidAppear:]
を設定します。
$arg1
、$arg2
は、フォーマットして出力した方が見やすいので、次のような NSString オブジェクトで出力してみます。
po [[NSString alloc] initWithFormat:@"🔰🔰🔰 %@ -[%@ %s]", [NSDate date], $arg1, $arg2]
これを Symbolic Breakpoint の Action の Debugger Command として設定します。
あとは、コンソールを 🔰🔰🔰 でフィルタするなどすれば、
viewDidAppear の都度、ビューコントローラクラス名などを確認することができるようになります。
独自の LLDB コマンドとして定義する
ブレークポイント追加のたびに po [[NSString alloc] 〜
と記述するのは面倒なので、
これを独自コマンド pm
(print method) として定義します。
独自コマンドの定義の仕方は次の通りです。
- 独自コマンドを定義した python スクリプトを作成
- python スクリプトを ~/.lldbinit-Xcode( または ~/.lldbinit )で読込む
python スクリプトを作成
独自コマンドを定義した python スクリプトを作成します。
今回は ~/.lldb/ 配下に print_method.py として作成しました。
# coding: utf-8
#!/usr/bin/python
import lldb
import commands
import os
# name: pm(print method)
command_name = "pm"
# implementation: print -[<ClassName: address> message]
command_implementation = "po [[NSString alloc] initWithFormat:@\"🔰🔰🔰 %@ -[%@ %s]\", [NSDate date], $arg1, $arg2]"
def cmd(debugger, command, result, dict):
debugger.HandleCommand(command_implementation)
def __lldb_init_module(debugger, internal_dict):
function = cmd.__name__
file_name = os.path.basename(__file__).split(".")[0]
debugger.HandleCommand("command script add -f %s.%s %s" % (file_name, function, command_name))
~/.lldbinit-Xcode で読込む
先に作成した python スクリプトを ~/.lldbinit-Xcode に読み込ませます。
command script import ~/.lldb/print_method.py
その後 Xcode を再起動します。
再起動することで、 .lldbinit-Xcode が読み込まれて、
LLDB デバッガで独自コマンド pm
が使用可能になります。
そして、独自コマンドは Symbolic Breakpoint の Action として使用することもできます。
これで、ブレークポイントの設定の手間を省くことができました。
Symbolic Breakpoint に独自コマンドを設定する
独自コマンド pm
が使えるようになったので、Debbuger Command に pm
と設定するだけで
ビューコントローラクラス名をコンソール出力できるようになりました。
pm
は viewDidAppear
に限らず、任意の Objective-C オブジェクトの任意のメソッドで利用できるので、
工夫次第で、Symbolic Breakpoint を利用する際の便利なツールになると思います。
ということで、Symbolic Breakpoint を使ってデバッグライフを楽しみましょう。