クライアント向けのiPadアプリの開発を引き継いでいます。すでにかなりの量の作業が行われており、全体がどのように実行されるように設計されているかをまとめようとしています。
私がやりたいことの1つは、アプリの実行時に呼び出されるメソッドをログに記録することです。起動からすべてのメソッドをログに記録することを目的としたカスタムDTraceスクリプトを見ましたが、Instrumentsで実行すると結果が得られません。
メソッドをログに記録する最良の方法は何ですか?
同様の質問に対するtcの回答に触発されて ここ 、アプリケーションでobjc_msgSend()がトリガーされるたびにクラスとメソッド名をログアウトするデバッグブレークポイントアクションをまとめました。これは、 この回答 で説明したDTraceスクリプトと同様に機能します。
このブレークポイントアクションを有効にするには、新しいシンボリックブレークポイントを作成します(Xcode 4で、ブレークポイントナビゲーターに移動し、ウィンドウの左下にあるプラス記号を使用して新しいシンボリックブレークポイントを作成します)。シンボルをobjc_msgSend
とし、アクションの評価後に自動的に続行するように設定し、次のコマンドを使用してアクションをデバッガーコマンドに設定します。
printf "[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)),*(long *)($esp+8)
ブレークポイントは次のようになります。
これにより、アプリケーションに対して実行すると、次のようなメッセージがログアウトされます。
[UIApplication sharedApplication]
[UIApplication _isClassic]
[NSCFString getCString:maxLength:encoding:]
[UIApplication class]
[SLSMoleculeAppDelegate isSubclassOfClass:]
[SLSMoleculeAppDelegate initialize]
私がどこでメモリアドレスを取得したのか疑問に思っている場合は、Objective-Cランタイム内部の このPhrackの記事 を読んでください。上記のメモリアドレスはシミュレータに対してのみ機能するため、iOSデバイス上のアプリケーションに対して実行するにはこれを微調整する必要がある場合があります。 Collinは、デバイスでこれを実行するために、 彼の答え で次の変更を提案しています。
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
また、アプリケーションで呼び出されたすべてのメソッドをログアウトすると、情報に圧倒されることがわかると思います。いくつかの条件を使用してこれをフィルタリングできる場合がありますが、これがコードの実行方法を学習するのに役立つかどうかはわかりません。
LLDBを使用している場合は、次のデバッガーコマンドを使用する必要があります。これらはXcode4.6でテストされました。
デバイス:
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($r0),$r1)
シミュレータ:
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)), *(long *)($esp+8))
デバイスのXcode6でアプリコードをトレースするには、次のデバッガー式を使用する必要がありました。
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)
Brad Larsonのアプローチは、デバッガコマンドを使用してデバイス上で実行するように適合させることができます。
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
詳細については、テクニカルノートをご覧ください: technotes
そのように呼び出す必要がある後のxcodeバージョン
expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )
Macでarm/x86_64アーキテクチャプロセスとして実行されるiOSsimulator
アプリの場合
Symbolic Breakpoint
シンボルと次のobjc_msgSend
を使用してDebugger Command
を作成します
p (void)printf("[%s, %s]\n", (char*)object_getClassName($arg1), $arg2)
p
はexpr --
のエイリアスです
ソースは SO回答
仲間の開発者が、同じ2つのログステートメントを各メソッドに追加するように教えてくれました。 1つは最初の行、もう1つは最後の行です。彼は自分のプロジェクトに対してこれを自動的に行うスクリプトを持っていると思いますが、結果は次のとおりです。
NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
コンソールで、これは次のようなものを吐き出します:
<<< Entering -[MainListTableViewController viewDidLoad] >>>
何が起こっているかを追跡するのに非常に役立ちます。