35

「内部」で何が発生するかをよりよく理解するために、アプリケーション内で発生する通知を完全に追跡したいと思います。

私はナイーブですが、最初に試したのは次のように登録することでした。

私のアプリのどこか:

{
    [...]
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(traceNotifications:) name:nil object:nil];
    [...]
}

- (void)traceNotifications:(NSNotification *)notification
{
    NSLog(@"received notification %@", [notification name]);
}

私は実際にその方法で多くの通知を受け取ります。しかし、ある時点でアプリケーションがクラッシュします。スタックトレースは、realizeClassのEXC_BAD_ACCESSでクラッシュしていることを示しています。これは、私の経験から、割り当て解除後に何かが呼び出されたことを示しています。私の観察対象はまだ生きていますが、そのデロケーターは(まだ)呼び出されていません。

次に試したのは、ブレークポイントを設定し、ブレークポイントがトラップされるたびにgdb-console内で-[NSNotificationCenter postNotification:]実行することでした。po {NSNotification *}($ebp+16)それはいくつかの通知を明らかにしましたが、私が期待/期待しているすべてではありませんでした。たとえば、私のアプリケーションは向きの変更を適切に処理しますが、デバイスの向きを変更するときに(シミュレーターで)通知がトラップされることはありません。

私は何が欠けていますか?NSNotificationCenterを確実に監視する方法(ツールなど)はありますか?

ヒントをありがとう。

4

5 に答える 5

60

私が仕事に取り掛かった唯一の解決策は、ブレークポイントを使用することでした。

(CoreFoundation)にブレークポイントを追加し、__CFXNotificationPost_oldそれをDebuggerCommandにバンドルしましたpo {NSNotification *}($ebp+12)。これはすべて、XcodeGUI内でうまく実行できます。

  • Xcodeアプリケーションメニュー(画面上部)の[実行]をクリックします
  • 「デバッガ」を選択します
  • デバッガウィンドウ内で[表示-ブレークポイント]をクリックします
  • 「EnterSymbol-Name」行をクリックして「__CFXNotificationPost_old」と入力します
  • 右端の「+」をクリックしてください
  • そのドロップダウンリストで[デバッガコマンド]を選択します
  • 「po{NSNotification*}($ ebp + 12)」と入力します
  • (下部にある[ログ]チェックボックスをオンにして、ログをアクティブにすることもできます)
  • Xcode内からsimulator-debug-sessionでアプリを実行します

NSNotificationが投稿されるたびにアプリは実行を停止し、gdb-console内に表示します。

gdb内にトレースポイントを作成しようとしましたが、Xcodegdb内のトレースポイントアクションにバグがあるように見えるため失敗しました。

また、カスタムのInstruments Dtraceスクリプトを作成しようとしましたが、DtraceKarateの強度が十分でないため失敗しました。

後者のオプションのいずれかをうまく機能させることができた場合は、先に進んで代替回答として投稿してください-私はそれらを賛成して、お気に入りのオプションとしてマークします。

アップデート

この質問から何年も経って、CoreFoundationレベルですべての通知をトラップする正しい方法を見つけました。

これがその方法です。

void MyCallBack (CFNotificationCenterRef center,
                 void *observer,
                 CFStringRef name,
                 const void *object,
                 CFDictionaryRef userInfo)
{
    NSLog(@"name: %@", name);
    NSLog(@"userinfo: %@", userInfo);
}

CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 
    NULL, 
    MyCallBack, 
    NULL, 
    NULL,  
    CFNotificationSuspensionBehaviorDeliverImmediately);

以前、CoreFoundationのインターフェースを詳しく調べていなかったことを少し恥ずかしく思います。

于 2010-09-17T19:31:02.170 に答える
21

Hey Till —通知をよく使用しますが、デバッグにも深刻な問題がありました。最近、プロセスを少し簡単にするSpark Inspector(http://sparkinspector.com/ )というアプリをリリースしました。アプリにフレームワークを追加すると、NSNotificationCenterがスウィズルし、アプリで送受信されたすべての通知のテーブルと、それらが送信されたスタックトレース、およびそれらを監視したすべてのメソッドのリストを表示できます。約3年遅れていることは知っていますが、役立つかもしれません。

ここに画像の説明を入力してください

于 2013-08-15T05:31:15.673 に答える
17

投稿された質問が古いことは知っていますが、数行のコードで応答すると思いました。
このブロックを介して、アプリの実行中に投稿されたすべての通知を確認できます。

  [[NSNotificationCenter defaultCenter] addObserverForName:nil
                                                    object:nil
                                                     queue:nil
                                                 usingBlock:^(NSNotification *notification) {
    NSLog(@"%@", notification.name);
  }];

これを適切なViewControllerのviewWillAppearメソッドに追加します。(もちろん、あらゆる種類の配布用にアプリを準備するときは、コードからこれを削除する必要があります。)

また、必ずこれを追加してください。

[[NSNotificationCenter defaultCenter] removeObserver:self];

選択したViewControllerの対応するviewWillDisappearメソッドに。

更新:同じ答えですが、Swiftでは:

override func viewWillAppear(animated: Bool) {
  super.viewWillAppear(animated)
  NSNotificationCenter.defaultCenter().addObserverForName(nil, 
                                                  object: nil, 
                                                   queue: nil) { 
                                                     note in
    print(note.name + "\r\n")
  }
}

override func viewWillDisappear(animated: Bool) {
  NSNotificationCenter.defaultCenter().removeObserver(self)
  super.viewWillDisappear(animated)
}
于 2015-05-04T17:46:35.927 に答える
11

デバッグの目的で、プロジェクトにコードを追加するよりも、ブレークポイントの方が実際に優れていることがわかりました。しかし、@Tillのソリューションは私にはうまくいかなかったようです。私はオンラインで別の解決策を見つけ、それを少し調整しました。

シンボリックブレークポイント

  • 記号-[NSNotificationCenter postNotificationName:object:userInfo:]
  • 状態((NSRange)[$arg3 rangeOfString:@"^(_|NS|UI)" options:1024]).length == 0
  • アクション:デバッガーコマンドpo $arg3
  • アクションを評価した後、自動的に続行します

ノート:

  • _条件は、、、NSまたはで始まる通知UIが表示されないようにすることです。
  • 1024を参照しNSRegularExpressionSearchますが、そのブレークポイントでは使用できないようです。
  • このブレークポイント()の戻り値とは異なる値(または)に評価されるように見えるため、.length == 0代わりにを使用します。.location == NSNotFoundNSNotFound-1(NSUInteger)184467440737095516159223372036854775807
于 2016-10-25T05:16:35.207 に答える
1

@Swift5.0およびXcode11のソリューションまで:

CFNotificationCenterAddObserver(
    CFNotificationCenterGetLocalCenter(),
    nil,
    { (notificationCenter, _, notificationName, _, dictionary) in
        print(notificationName)
        print(dictionary)
}, nil, nil, .deliverImmediately)
于 2019-10-19T14:27:34.317 に答える