Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSNotificationCenter removeObserver: in dealloc and thread-safety

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:?

like image 889
teerapap Avatar asked Dec 17 '12 08:12

teerapap


People also ask

Is NSNotificationCenter thread safe?

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.

How do I delete an observer in Objective C?

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.

How do I delete all observers in Swift?

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.


2 Answers

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.

like image 138
felinira Avatar answered Oct 27 '22 11:10

felinira


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.

like image 41
ksh Avatar answered Oct 27 '22 10:10

ksh