Objective-C: Where to remove observer for NSNotification?
Solution 1
The generic answer would be "as soon as you no longer need the notifications". This is obviously not a satisfying answer.
I'd recommend, that you add a call [notificationCenter removeObserver: self]
in method dealloc
of those classes, which you intend to use as observers, as it is the last chance to unregister an observer cleanly. This will, however, only protect you against crashes due to the notification center notifying dead objects. It cannot protect your code against receiving notifications, when your objects are not yet/no longer in a state in which they can properly handle the notification. For this... See above.
Edit (since the answer seems to draw more comments than I would have thought) All I am trying to say here is: it's really hard to give general advice as to when it's best to remove the observer from the notification center, because that depends:
- On your use case (Which notifications are observed? When do they get send?)
- The implementation of the observer (When is it ready to receive notifications? When is it no longer ready?)
- The intended life-time of the observer (Is it tied to some other object, say, a view or view controller?)
- ...
So, the best general advice I can come up with: to protect your app. against at least one possible failure, do the removeObserver:
dance in dealloc
, since that's the last point (in the object's life), where you can do that cleanly. What this does not mean is: "just defer the removal until dealloc
is called, and everything will be fine". Instead, remove the observer as soon as the object is no longer ready (or required) to receive notifications. That is the exact right moment. Unfortunately, not knowing the answers to any of the questions mentioned above, I cannot even guess, when that moment would be.
You can always safely removeObserver:
an object multiple times (and all but the very first call with a given observer will be nops). So: think about doing it (again) in dealloc
just to be sure, but first and foremost: do it at the appropriate moment (which is determined by your use case).
Solution 2
Since iOS 9 it's no longer necessary to remove observers.
In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated.
Solution 3
Note : This has been tested and working 100% percent
Swift
override func viewWillDisappear(animated: Bool){
super.viewWillDisappear(animated)
if self.navigationController!.viewControllers.contains(self) == false //any other hierarchy compare if it contains self or not
{
// the view has been removed from the navigation stack or hierarchy, back is probably the cause
// this will be slow with a large stack however.
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
PresentedViewController:
override func viewWillDisappear(animated: Bool){
super.viewWillDisappear(animated)
if self.isBeingDismissed() //presented view controller
{
// remove observer here
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
Objective-C
In iOS 6.0 > version
, its better to remove observer in viewWillDisappear
as viewDidUnload
method is deprecated.
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
There is many times its better to remove observer
when the view has been removed from the navigation stack or hierarchy
.
- (void)viewWillDisappear:(BOOL)animated{
if (![[self.navigationController viewControllers] containsObject: self]) //any other hierarchy compare if it contains self or not
{
// the view has been removed from the navigation stack or hierarchy, back is probably the cause
// this will be slow with a large stack however.
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
}
}
PresentedViewController:
- (void)viewWillDisappear:(BOOL)animated{
if ([self isBeingDismissed] == YES) ///presented view controller
{
// remove observer here
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
}
}
Solution 4
If the observer is added to a view controller, I strongly recommend adding it in viewWillAppear
and removing it in viewWillDisappear
.
Solution 5
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Related videos on Youtube
Zhen
Updated on December 04, 2020Comments
-
Zhen over 3 years
I have an objective C class. In it, I created a init method and set up a NSNotification in it
//Set up NSNotification [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getData) name:@"Answer Submitted" object:nil];
Where do I set the
[[NSNotificationCenter defaultCenter] removeObserver:self]
in this class? I know that for aUIViewController
, I can add it into theviewDidUnload
method So what needs to be done if I just created an objective c Class?-
onnoweb about 13 yearsI put it in the dealloc method.
-
Zhen about 13 yearsThe dealloc method was not automatically created for me when I created the objective c class, so it's ok for me to add it in?
-
petershine about 13 yearsYes, you can implement
-(void)dealloc
and then addremoveObserser:self
in it. This is the most recommended way to putremoveObservers:self
-
wcochran about 11 yearsIs it still ok to put in the
dealloc
method in iOS 6? -
Phil about 11 yearsYes, it is ok to use dealloc in ARC projects as long as you do not call [super dealloc] (you will get a compiler error if you call [super dealloc]). And yes, you can definitely put your removeObserver in dealloc.
-
mcfedr over 10 yearsDealloc still exists, but it is not the place for this, your dealloc will never be called because of the notificationcenter references to your object
-
Shamsiddin Saidov about 7 years@mcfedr what do you offer when NotificationCenter references to an object?
-
mcfedr about 7 years@Shamsiddin That comment of mine is actually wrong. NotificationCentre doesnt keep strong references to objects.
-
-
Dirk about 13 yearsI'd turn the order of these instructions around... Using
self
after[super dealloc]
makes me nervous... (even if the receiver is unlikely to actually dereference the pointer in any way, well, you never know, how they implementedNSNotificationCenter
) -
Legolas about 13 yearsHm. it has worked for me. Have you noticed any unusual behavior ?
-
Dirk about 13 yearsNope. This was just a general remark. It just feels like using a
malloc
ed pointer after the call tofree
to me... -
jscs about 13 yearsDirk is right -- this is incorrect.
[super dealloc]
must always be the last statement of yourdealloc
method. It destroys your object; after it runs, you don't have a validself
anymore. /cc @Dirk -
Legolas about 13 years@Josh : Hey dude. So are you sure about this ? So you are saying that all
dealloc
statements do not work (or) do not mean anything if I do this way ? -
jscs about 13 years@Legolas: They may work most of the time, but they're not safe.
-
Legolas about 13 years@Josh: Well yeah. They have worked for me so far. Let me try switching things in your way. May be these were the reasons for the
memory leaks
-
Deamon about 12 yearsIf using ARC on iOS 5+, I think
[super dealloc]
is not needed anymore -
marko over 11 yearsWelcome to StackOverflow. Please checkout the MarkDown FAQ (question-mark icon next to the question/answer edit box). Using Markdwon will improve the usability of your answer.
-
Isaac Overacker over 11 yearsI'm curious, @RickiG: why do you recommend using
viewWillAppear
andviewWillDisappear
for viewControllers? -
RickiG over 11 years@IsaacOveracker a few reasons: your setup up code (eg. loadView and viewDidLoad) could potentially cause the notifications to be fired and your controller needs to reflect that before it shows. If you do it like this there are a few benefits. At the moment you decided to "leave" the controller you don't care about the notifications and they wont cause you to do logic while the controller is being pushed off screen etc. There are special cases where the controller should receive notifications when it is off-screen I guess you can't do this. But events like that should probably be in your model.
-
RickiG over 11 years@IsaacOveracker also with ARC it would be weird to implement dealloc to unsubscribe to notifications.
-
lnafziger over 11 yearsLots of people are still writing code for older versions of iOS than iOS6.... :-)
-
Alex over 11 yearsIn ARC you can use this code but without the line [super dealloc]; You can see more here: developer.apple.com/library/ios/#releasenotes/ObjectiveC/…
-
tapmonkey over 11 years@pixelfreak stronger, it is not allowed under ARC to call [super dealloc]
-
wcochran about 11 yearsExcept a controller may still want notifications when its view is not showing (e.g. to reload a tableView).
-
qix about 11 yearsWhat if you had a regular NSObject be the observer of a notification? Would you use dealloc in this case?
-
MobileMon about 11 yearsThis is not safe with ARC and could potentially cause a leak. See this discsussion: cocoabuilder.com/archive/cocoa/311831-arc-and-dealloc.html
-
Dirk about 11 years@MobileMon The article you linked to seems to make my point. What am I missing ?
-
MobileMon almost 11 yearsI suppose it should be noted in that one should remove observer somewhere else other than dealloc. For example, viewwilldisappear
-
Dirk almost 11 years@MobileMon -- yes. I hope, that that's the point I am getting across with my answer. Removing the observer in
dealloc
is only a last line of defence against crashing the app due to a later access to a decallocated object. But the proper place to unregister an observer is usually somewhere else (and often, much earlier in the object's life-cycle). I am not trying to say here "Hey, just do it indealloc
and everything will be fine". -
Dirk almost 11 years@MobileMon "For example,
viewWillDisappear
" The problem with giving a concrete advise is, that it really depends on what kind of object you register as observer for what kind of event. It may be the right solution to unregister an observer inviewWillDisappear
(orviewDidUnload
) forUIViewController
s, but that really depends on the use case. -
MobileMon almost 11 yearsYeah I think I misread your answer. I believe I meant to put it on the answer below, sorry about that
-
Richard almost 11 years@wcochran automatically reload/refresh in
viewWillAppear:
-
Alexandre almost 11 yearsSo is it still needed to removeObserver in dealloc using ARC ?
-
quantumpotato almost 11 yearsARC forbits explicit calls to dealloc, eg [super dealloc]. This doesn't work for iOS 6.
-
Legolas almost 11 yearsIts ok to put there. You need to basically place in that based on the life cycle of the VC.
viewDidDisappear
is a good place. -
mcfedr over 10 yearsThis will cause leaks! Dealloc will never be called because the notificationCenter is still holding references to your object
-
Dirk over 10 years@mcfedr: no, the
NSNotificationCenter
does not retain objects added withaddObserver:selector:name:object:
. It doesn't specify this explicitly in the documentation, but you can infer it from sentences like "Be sure to invoke removeObserver: or removeObserver:name:object: before notificationObserver or any object specified in addObserver:selector:name:object: is deallocated." (or you can run a small test program and verify the behaviour, as I just did to be sure). -
lekksi over 10 yearsOf those what I've tried, with iOS7 this is the best way to register/remove observers when working with UIViewControllers. The only catch is that, in many cases you don't want the observer to be removed when using UINavigationController and pushing another UIViewController to the stack. Solution: You can check if the VC is being popped in viewWillDisappear by calling [self isBeingDismissed].
-
Dirk over 10 years@lekksi -- Unfortunately, the answer you favour will only make sense for
UIViewController
s. If we are talking about arbitrary application-defined classes (as the OP explicitly does), you simply cannot give general advice as to when it's best to remove an observer from the notification center. And even in the case of aUIViewController
descendant, you do not know in general, whetherviewWillAppear:
/viewWillDisappear:
is really appropriate. -
lekksi over 10 years@Dirk You are right, my wording for the previous comment was not exact enough, sorry about that. :) What I tried to state is that: When working with ViewControllers, iOS7 and ARC (as many of us do nowadays), it might be better to do e.g. as suggested in RickiG's answer than use dealloc.
-
Matrosov Oleksandr about 10 years@Prince can you explain why viewWillDisapper better then dealloc? so we have add observer to self, so when the self will be dropped from memory it will call dealloc and then all observers will be deleted, is this not a good logic.
-
Jonathan Lin about 10 yearsPopping the view controller from navigation controller may not cause
dealloc
to be called immediately. Going back into the view controller may then cause multiple notifications if observer is added in initialization commands. -
Ans almost 10 yearsits up to you .. you can remove them in
viewWillDisapper
or inviewDidDisapper
methods. -
SarpErdag over 9 yearsI agree with this answer. I experience memory warnings and leaks leading to crashes after intensive use of the app if I don't remove the observers in viewWillDisappear.
-
cbowns over 9 yearsCalling
removeObserver:self
in any of theUIViewController
lifecycle events is almost guaranteed to ruin your week. More reading: subjective-objective-c.blogspot.com/2011/04/… -
Christopher King over 9 yearsPutting the
removeObserver
calls inviewWillDisappear
as indicated is definitely the right way to go if the controller is being presented viapushViewController
. If you put them indealloc
instead thendealloc
will never be called -- in my experience at least... -
raw3d over 9 yearshow to do the same in swift without type casting [self.navigationController viewControllers] to NSArray ??
-
wuf810 about 9 yearsThe EDIT suggesting checking the navigation hierarchy for the controller is the perfect solution for @wcochran's point. Very helpful
-
RickiG almost 9 yearsIt is hard to say if this is right as the context is important. It is mentioned a few times already, but dealloc makes little sense in an ARC context (which is the only context by now). It is also not predictable when dealloc is called - viewWillDisappear is easier to control. A side note: If your child needs to communicate something to it's parent the delegate pattern sounds like a better choice.
-
Borzh almost 9 yearsIt is better still to remove observer in dealloc, but without the call to super obviously (it is done automatically by ARC).
-
fir over 7 yearsMay be they will not send messages to observers, but I believe they will keep a strong reference to them as I understand. In that case all observers will stay in memory and produce a leak. Сorrect me if I am wrong.
-
Sebastian over 7 yearsThe linked documentation goes into detail about that. TL;DR: it's a weak reference.
-
TheEye over 6 yearsbut of course it's still necessary in case you keep the object referencing them around and just don't want to listen to the notifications anymore
-
Shrikant Phadke about 4 yearswhich statement is right from below and why !!!! 1) [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(proximityChanged) name: @"UIDeviceProximityStateDidChangeNotification" object:[UIDevice currentDevice]]; 2) [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(proximityChanged) name: UIDeviceProximityStateDidChangeNotification object:[UIDevice currentDevice]];
-
Alexander Volkov over 3 yearsWrong! You should never unsubscribe in
deinit
because it's useless. When instance is clean from memory iOS unsubscribes it automatically, then it callsdeinit
, so it's useless. -
Alexander Volkov over 3 yearsThis is wrong answer. If dealloc is called, then instance is already unsubscribed (by the system).
-
Morten Holmgaard over 3 years@AlexanderVolkov Please remember this answer is 5 years old, when swift was brand new. At that time it was the solution but it has changed since.
-
Alexander Volkov over 3 yearsNope. If deinit is called, then iOS automatically unsubscribed the observer. This is equal in ObjC and in Swift, it's system dependent, not language. Probably I wrong, but then provide a reference to documentation.