代码之家  ›  专栏  ›  技术社区  ›  Till

NSNotificationCenter捕获和跟踪所有NSNotifications

  •  32
  • Till  · 技术社区  · 14 年前

    为了更好地理解引擎盖下发生的事情,我想对我的应用程序中发生的任何通知做一个完整的跟踪。

    虽然我很中庸,但我第一个尝试的就是这样注册:

    在我的应用程序中:

    {
        [...]
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(traceNotifications:) name:nil object:nil];
        [...]
    }
    
    - (void)traceNotifications:(NSNotification *)notification
    {
        NSLog(@"received notification %@", [notification name]);
    }
    

    我确实收到了很多这样的通知。但在某个时候,应用程序确实崩溃了。堆栈跟踪显示它正在realizeClass中使用EXC\u BAD\u访问崩溃,根据我的经验,这确实表明在释放它之后调用了一些东西。我的观察对象虽然还活着,但它的deallocator还没有被调用。

    接下来我尝试的是设置一个断点 -[NSNotificationCenter postNotification:] 然后跑 po {NSNotification *}($ebp+16) 在gdb控制台中,每当我的断点被捕获时。这确实透露了一些通知,但并不是我所期望的全部。例如,我的应用程序确实能够正确地处理方向更改,但是在重新定位设备(在模拟器中)时,我看不到任何通知被捕获。

    谢谢你的提示。

    4 回复  |  直到 14 年前
        1
  •  9
  •   Community CDub    8 年前

    出于调试目的,我发现断点实际上比向项目中添加代码要好。然而, @Till's solution 似乎不适合我。我发现 another solution online

    符号断点

    • 符号 -[NSNotificationCenter postNotificationName:object:userInfo:]
    • 条件 : ((NSRange)[$arg3 rangeOfString:@"^(_|NS|UI)" options:1024]).length == 0
    • :调试器命令 po $arg3
    • 评估操作后自动继续

    • 条件是阻止任何以 _ , NS ,或 UI 从被显示。
    • 1024 NSRegularExpressionSearch ,该断点似乎不可用。
    • 我用 .length == 0 .location == NSNotFound 因为 NSNotFound -1 (NSUInteger)18446744073709551615 )大于此断点中的返回值( 9223372036854775807 ).
        2
  •  60
  •   Till    13 年前

    唯一的解决办法就是使用断点。

    __CFXNotificationPost_old (CoreFoundation)并将其与调试器命令捆绑在一起 po {NSNotification *}($ebp+12) . 所有这些都可以在Xcode GUI中很好地实现:

    • 选择“调试器”
    • 单击“输入符号名称”行并输入“\ucfxnotificationpost\u old”
    • 在下拉列表中选择“调试器命令”
    • (您也可以通过选中底部的“日志”复选框来激活日志记录)
    • 在Xcode中的模拟器调试会话中运行应用程序

    我确实尝试在gdb中创建一个跟踪点,但是失败了,因为Xcode gdb中的跟踪点操作似乎有问题——或者我太笨了,无法让它们工作。

    我还试图创建一个定制的Dtrace脚本,但失败了,因为我的Dtrace空手道不够强。

    如果你设法让后一种选择中的任何一种发挥作用,请继续并把它们作为一个替代答案张贴-我会投票,并将它们标记为最受欢迎的一个。

    问了很久之后,我发现 正确的 在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的接口。

        3
  •  21
  •   Ben Gotow Dmitry Nogin    11 年前

    嘿,我经常使用通知,调试它们时也遇到了一些严重的问题。我最近发布了一个名为Spark Inspector的应用程序( http://sparkinspector.com/ )这使得这个过程更容易一些。你给你的应用程序添加了一个框架,它会切换到NSNotificationCenter,这样你就可以看到一个表,其中包含了在你的应用程序中发送和接收的所有通知,以及它们发送到的堆栈跟踪,以及观察到它们的所有方法的列表。我知道已经晚了三年了,但可能会有帮助!

    enter image description here

        4
  •  17
  •   nekno    9 年前


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

    将其添加到相应视图控制器的viewWillAppear方法中。(当然,在为任何类型的分发准备应用程序时,都应该将其从代码中删除。)

    另外,请务必添加以下内容:

    [[NSNotificationCenter defaultCenter] removeObserver:self];
    

    到所选视图控制器的相应viewWillDisappear方法。

    更新:

    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)
    }
    
        5
  •  1
  •   Baran Emre    5 年前

    @直到溶液进入 Swift 5.0和Xcode 11 :

    CFNotificationCenterAddObserver(
        CFNotificationCenterGetLocalCenter(),
        nil,
        { (notificationCenter, _, notificationName, _, dictionary) in
            print(notificationName)
            print(dictionary)
    }, nil, nil, .deliverImmediately)