web-dev-qa-db-ja.com

iOSアプリで使用されるすべてのメソッドをログに記録する方法

クライアント向けのiPadアプリの開発を引き継いでいます。すでにかなりの量の作業が行われており、全体がどのように実行されるように設計されているかをまとめようとしています。

私がやりたいことの1つは、アプリの実行時に呼び出されるメソッドをログに記録することです。起動からすべてのメソッドをログに記録することを目的としたカスタムDTraceスクリプトを見ましたが、Instrumentsで実行すると結果が得られません。

メソッドをログに記録する最良の方法は何ですか?

44
Phil John

同様の質問に対するtcの回答に触発されて ここ 、アプリケーションでobjc_msgSend()がトリガーされるたびにクラスとメソッド名をログアウトするデバッグブレークポイントアクションをまとめました。これは、 この回答 で説明したDTraceスクリプトと同様に機能します。

このブレークポイントアクションを有効にするには、新しいシンボリックブレークポイントを作成します(Xcode 4で、ブレークポイントナビゲーターに移動し、ウィンドウの左下にあるプラス記号を使用して新しいシンボリックブレークポイントを作成します)。シンボルをobjc_msgSendとし、アクションの評価後に自動的に続行するように設定し、次のコマンドを使用してアクションをデバッガーコマンドに設定します。

printf "[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)),*(long *)($esp+8)

ブレークポイントは次のようになります。

Breakpoint action

これにより、アプリケーションに対して実行すると、次のようなメッセージがログアウトされます。

[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

また、アプリケーションで呼び出されたすべてのメソッドをログアウトすると、情報に圧倒されることがわかると思います。いくつかの条件を使用してこれをフィルタリングできる場合がありますが、これがコードの実行方法を学習するのに役立つかどうかはわかりません。

55
Brad Larson

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))
19
warhammerkid

デバイスのXcode6でアプリコードをトレースするには、次のデバッガー式を使用する必要がありました。

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)

Brad Larsonのアプローチは、デバッガコマンドを使用してデバイス上で実行するように適合させることができます。

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

詳細については、テクニカルノートをご覧ください: technotes

5
Collin

そのように呼び出す必要がある後のxcodeバージョン

expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )
4
Ali Kıran

シミュレーターのメソッドを64ビットでログに記録する場合は、代わりに次のコマンドを使用してください。

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($rdi), (char *) $rsi)

または、それが機能しない場合は、次のようにログに記録します。

enter image description here

主なアイデアは、オブジェクト(自己)に$ rdiを使用し、セレクターに$ rsiを使用することです。

1
TGO

Macでarm/x86_64アーキテクチャプロセスとして実行されるiOSsimulatorアプリの場合

Symbolic Breakpointシンボルと次のobjc_msgSendを使用してDebugger Commandを作成します

p (void)printf("[%s, %s]\n", (char*)object_getClassName($arg1), $arg2)

pexpr --のエイリアスです

enter image description here

ソースは SO回答

1
yoAlex5

仲間の開発者が、同じ2つのログステートメントを各メソッドに追加するように教えてくれました。 1つは最初の行、もう1つは最後の行です。彼は自分のプロジェクトに対してこれを自動的に行うスクリプトを持っていると思いますが、結果は次のとおりです。

NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);

コンソールで、これは次のようなものを吐き出します:

 <<< Entering -[MainListTableViewController viewDidLoad] >>>

何が起こっているかを追跡するのに非常に役立ちます。

1
DenVog