I'm using ARC and I'm calling [[NSNotificationCenter defaultCenter] removeObserver:someObserver];
in observer's dealloc
.
From NSNotificationCenter Class Reference
Be sure to invoke this method (or removeObserver:name:object:) before notificationObserver or any object specified in addObserver:selector:name:object: is deallocated.
NSNotificationCenter does not retain the observer.
Q1: Is NSNotificationCenter
thread-safe?
In case, the observer is being deallocated(and removing observer from the notification center) and another thread post a notification at the same time.
I encounter random crash and I suspect this is the case.
Q2: Is this situation possible?
Q3: Does it lead to EXC_BAD_ACCESS
?
Q4: Then, is it safe to call [[NSNotificationCenter defaultCenter] removeObserver:someObserver];
in observer's dealloc
?
Q5: If it is not safe, where should I call removeObserver:
?
In most ways that matter NSNotificationCenter is thread safe. You can add/remove observers from any thread and you can post notifications from any thread.
When removing an observer, remove it with the most specific detail possible. For example, if you used a name and object to register the observer, use removeObserver:name:object: with the name and object.
Removing registered observer For Selector approach, use NotificationCenter. default. removeObserver(self, name: notificationName , object: nil) , to remove the observer. For Block based approach, save the token you obtained by registering for notification in a property.
I just stumbled into this problem myself: I had one notification just in the process of being sent (which always happens in the main thread) while the object was in the process of being deallocated from a background thread. I fixed it by simply performing removeObserver
in the main thread and waiting:
- (void)removeNotificationCenterObserver
{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self];
}
- (void)dealloc
{
[self performSelectorOnMainThread:@selector(removeNotificationCenterObserver) withObject:self waitUntilDone:YES];
}
This waits until the current run loop cycle ends and executes this message at the beginning of the next run loop cycle. This ensures that any functions that are still running will finish.
Yes, NSNotificationCenter
doesn't retain observer, but it still has a pointer to it in it's dispatch table.
Q1: Quoting Apple docs
Regular notification centers deliver notifications on the thread in which the notification was posted. Distributed notification centers deliver notifications on the main thread. At times, you may require notifications to be delivered on a particular thread that is determined by you instead of the notification center. For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread.
Q2,3: Yes.
Q4,5: AFAIK it's safe unless you stumble into circular reference.
I usually add/remove in -viewWillAppear:
/-viewWillDisappear:
for UIViewControllers and -init
/dealloc
for other classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With