For some better understanding on what happens “under the hood”, I would love to do a complete trace of any notifications happening within my application.
Naïve as I
Hey Till—I use notifications a lot, and I had some serious problems debugging them as well. I recently released an app called the Spark Inspector (http://sparkinspector.com/) that makes the process a bit easier. You add a framework to your app, and it swizzles NSNotificationCenter so you can see a table of all of the notifications sent and received in y our app, with the stack traces where they were sent and the list of all the methods that observed them. I know it's about three years late, but it may help!
I know the posted question is old, but I figured I'd respond with a couple lines of code.
You can see all the notifications posted while your app is running via this block:
[[NSNotificationCenter defaultCenter] addObserverForName:nil
object:nil
queue:nil
usingBlock:^(NSNotification *notification) {
NSLog(@"%@", notification.name);
}];
Add that to the viewWillAppear method of an appropriate view controller. (Of course, you should remove this from your code when preparing your app for any kind of distribution.)
Also, be sure to add this:
[[NSNotificationCenter defaultCenter] removeObserver:self];
To your selected view controller's corresponding viewWillDisappear method.
UPDATE: Same answer, but in 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)
}
The only solution I got to work was using breakpoints.
I added a breakpoint at __CFXNotificationPost_old
(CoreFoundation) and bundled that with a Debugger Command po {NSNotification *}($ebp+12)
. All of this is nicely doable within the Xcode GUI:
The app will stop its execution whenever a NSNotification is posted and display it within the gdb-console.
I did try to create a tracepoint within gdb but failed because the tracepoint actions within Xcode gdb seem to buggy - or maybe I am just too stoopid to get them working.
I also tried to create a custom Instruments Dtrace script, but failed as my Dtrace Karate just isnt strong enough.
If you manage to get any of the latter options to work, please go ahead and post them as an alternative answer - I will upvote and mark them as the favored one.
UPDATE
Ages after this question, I found the right way of trapping all notifications on the CoreFoundation level.
This is how it can be done:
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);
I actually feel a little ashamed that I did not look closer at CoreFoundation's interface before.
For debugging purposes, I find that a breakpoint is actually better than adding code to the project. However, @Till's solution didn't seem to work for me. I found another solution online, and tweaked it a bit.
Symbolic Breakpoint
- Symbol:
-[NSNotificationCenter postNotificationName:object:userInfo:]
- Condition:
((NSRange)[$arg3 rangeOfString:@"^(_|NS|UI)" options:1024]).length == 0
- Action: Debugger Command
po $arg3
- Automatically continue after evaluating actions
Notes:
_
, NS
, or UI
from being displayed.1024
refers to NSRegularExpressionSearch, which doesn't seem to be available for that breakpoint..length == 0
instead of .location == NSNotFound
because NSNotFound
seems to evaluate to a different value (-1
or (NSUInteger)18446744073709551615
) than the returned value in this breakpoint (9223372036854775807
).@Till solution in Swift 5.0 & Xcode 11:
CFNotificationCenterAddObserver(
CFNotificationCenterGetLocalCenter(),
nil,
{ (notificationCenter, _, notificationName, _, dictionary) in
print(notificationName)
print(dictionary)
}, nil, nil, .deliverImmediately)