I\'m using ARC and I\'m calling [[NSNotificationCenter defaultCenter] removeObserver:someObserver];
in observer\'s dealloc
.
From NSNotification
I've wondered the same thing, and I can't find it documented. Here's what I think is going on.
removeObserver:
is not thread safe in the way that you want it to be.
Think about the following situation. The last reference to the observer is released while executing code on thread A. Thread A will call the observer's dealloc
method. At the same time, the observed object executes a [NSNotificcationCenter postNotificationName:object:]
from thread B. This leads to an unavoidable race condition. That is, a notification will be in flight while your object is within its dealloc
method.
- (void)init {
...
[[NSNotificcationCenter defaultCenter] addObserver:self
selector:@selector(callback:)
name:@"whatever"
object:nil];
...
}
- (void)dealloc {
// If the observed object posts the notification on thread B while
// thread A is here, there's a race! At best, thread B will be
// in callback: while thread A is here in dealloc. That's probably
// not what you expect. The worst case is that thread B won't make
// make it to callback: until after thread A completes the dealloc
// and the memory has been freed. Likely crash!
[[NSNotificationCenter defaultCenter] removeObserver:self];
// If the observed object does the post when thread A is here,
// you'll be fine since the observation has been removed.
}
This isn't a problem for main thread objects that are only observing other main thread objects since, by definition, you can't get into the thread A and B scenario I described.
For multi-threaded cases, the only way to guarantee you'll avoid the problem is to ensure that the observation stops before the observer's refcount hits 0. If someone else is responsible for the observer's lifetime (i.e. you have any sort of term
or close
method), it's easy. If not, I don't know of a solution.