为了更好地了解“幕后”发生的情况,我希望对应用程序中发生的任何通知进行完整跟踪。
尽管我很天真,但我尝试的第一件事就是像这样注册:
我的应用程序中的某个位置:
{
[...]
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(traceNotifications:) name:nil object:nil];
[...]
}
- (void)traceNotifications:(NSNotification *)notification
{
NSLog(@"received notification %@", [notification name]);
}
我确实通过这种方式收到了很多通知。但在某些时候应用程序确实崩溃了。堆栈跟踪显示它在realizeClass中因EXC_BAD_ACCESS而崩溃,根据我的经验,这确实表明在释放后调用了某些东西。然而,我的观察对象仍然存在,它的释放器尚未被调用。
接下来我尝试的是向 -[NSNotificationCenter postNotification:]
设置断点,然后在 gdb- 内运行 po {NSNotification *}($ebp+16)
每当我的断点被捕获时控制台。这确实揭示了一些通知,但并不是我所期待/希望的全部。例如,我的应用程序确实可以正确处理方向更改,但在重新调整设备方向(在模拟器中)时我没有看到任何通知被捕获。
我错过了什么? 有没有一种方法(例如工具)可以可靠地观察 NSNotificationCenter?
感谢您的任何提示。
最佳答案
我唯一的解决方案是使用断点。
我在 __CFXNotificationPost_old
(CoreFoundation) 处添加了一个断点,并将其与调试器命令 po {NSNotification *}($ebp+12)
捆绑在一起。所有这些都可以在 Xcode GUI 中很好地完成:
- 单击 Xcode 应用程序菜单(屏幕顶部)上的“运行”
- 选择“调试器”
- 在调试器窗口中单击“Show-Breakpoints”
- 点击“输入符号名称”行并输入“__CFXNotificationPost_old”
- 点击最右侧的“+”
- 在该下拉列表中选择“调试器命令”
- 输入“po {NSNotification *}($ebp+12)
- (您可能还想通过选中底部的“日志”复选框来激活日志记录)
- 在 Xcode 内的模拟器调试 session 中运行您的应用
每当发布 NSNotification 时,应用程序都会停止执行,并将其显示在 gdb 控制台中。
我确实尝试在 gdb 中创建跟踪点,但失败了,因为 Xcode gdb 中的跟踪点操作似乎有问题 - 或者也许我太笨了,无法让它们工作。
我还尝试创建自定义 Instruments Dtrace 脚本,但失败了,因为我的 Dtrace Karate 不够强大。
如果您设法使后一个选项发挥作用,请继续将其作为替代答案发布 - 我将投票并将其标记为最喜欢的答案。
更新
在这个问题问了很久之后,我找到了在 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的界面。
关于iphone - NSNotificationCenter 捕获并跟踪所有 NSNotification,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3725234/