I set up a notification observer in my view controller's init method like so:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(saveState)
name:UIApplicationWillResignActiveNotification
object:nil];
Where is the best place to call removeObserver:name:object: for this notification. I'm currently calling it in my dealloc method, but wanted to know if that might cause problems.
No, you got it right. dealloc is the correct location to remove notification observers (unless you have some specific reason to need to remove the observer earlier).
You can always remove the observer in viewWillDisappear:, or when you are done using it and have no other need for it, you can place it in a function.
If the -saveState only need to execute once when active, then you can removeObserver inside the -saveState.
Related
I used to addObserver in viewDidLoad: and removeObserver in dealloc:. Code:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(refreshData)
name:AnyNotification
object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:AnyNotification
object:nil];
}
But according to some articles said, it's better to addObserver in viewDidAppear: and removeObserver in viewDidDisappear:. Code:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(refreshData)
name:AnyNotification
object:nil];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:AnyNotification
object:nil];
}
So, what's the better way to addObserver/removeObserver?
this depends on your scenario, usually the best approach is to add in viewDidLoad and remove in dealloc and in viewDidUnload (deprecated in iOS 9.0, use dealloc only), but there are some cases when you have same method in different classes like UI effects and want to call only current screen's method using notification, then you will have to add the observer in viewWillAppear and remove it in viewWillDisappear or viewDidAppear/viewDidDisappear
Edit:
A note from comments, thanks #honey.
Though now since iOS 9, you no longer need to care about removing the observer. See Apple release notes: "In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated..
I would normally put it in -viewDidAppear: and -viewDidDisapear: (or -viewWillAppear: and -viewWillDisappear:) simply because in every case I came across I'm only interested in the notification if the view is actually displayed.
It's probably a premature optimisation (your code for handling the notification could take some time, but might be useless if the view is not displayed), but then it's also no more code - it's the same code just in a different method...
Don't forget NSKeyValueObservingOptionInitial. I use it with viewWillAppear/viewWillDisappear so my UI is always up-do-date, even if I hide that view controller, saving resources because I will not update it until is shown again.
The best approach using NSNotifications is adding the observer when you need to observe for notifications and remove them when you don't need them anymore.
This could be on viewDidLoad:, viewWillAppear:, or when the user taps some button etc.
I will give you a little example:
My app has a tabbar, and in some of the view controllers, I'm displaying some info downloaded from internet (a tweet for example). I also have a class pooling for new data from server each 2 minutes, and as the server had new data, I updated the info on database. I will not use a delegate pattern to listen to DB changes, because I have so many view controllers displaying data, and it will be a very bad design making the delegate an array and looping to pass the data for every view controller. So, in this specific scenario, the best to do is to post a notification telling every VC that new data has come.
If your VC removes the delegate when the view disappears, only the current one will receive the notification and update the displaying contents.
You obviously could update the contents of the other VCs before display, on viewWillAppear: for example, but doing this the VC contents will be updated not only when necessary, but each time you change tabs.
It was only one example, where I tried to show you that for NSNotifications, is difficult to advise you when to add or remove observers when we don't have the entire description of how you app behaviours.
-viewWillAppear: + -viewWillDisappear: is better than -viewDidAppear: + -viewDidDisapear:, because they are always called the same number of times.
i have a viewcontroller .In it there is a nsnotification observer in it. i am posting the notification from another viewcontroller.but the nsnotification observers selector get fired two or sometimes three times. My question is that when i use [view removeFromSuperview];
to remove this viewcontrollers view ,is the notification observer removed? I have given this method at the dealloc method of the viewcontroller class
- (void)dealloc {
[super dealloc];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
No.
that method will be called when the viewcontrollers retain count becomes 0
You should add another method that will be called when the view is removed from the other viewcontroller and call
[[NSNotificationCenter defaultCenter] removeObserver:self];
For the issue that the selector is called multiple times, I would need to see more code - make sure that the line of code thats posting the notification isnt being called multiple times
NSNotification registered to whole app (or even for all operating system), not to single view or viewcontroller. You have need for remove observer in your action if it won't longer used. In this case you can handle only one posted notification.
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationForbidAdvPost object:nil];
I define postNotificationName:kNotificationForbidAdvPost in a .h file
Im my subclass of NSApplication, I import this .h file. And have a observer of this Notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(changeToRecordingStatus) name:kNotificationForbidAdvPost object:nil];
I am sure that the observer was added first, and then post the notification.
And I see the [UINotification default] in Debug. It have same memory address in two part of code.
Is there some mistake I have?
Thanks!
The documentation is pretty clear when it states that
The method specified by
notificationSelector must have one and
only one argument (an instance of
NSNotification).
http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000219-CHDCIGGB
So, I see your selector you are registering is changeToRecordingStatus when it must be changeToRecordingStatus:
- (void) changeToRecordingStatus: (NSNotification *) notification;
I have try that add a arugument, but it is still not worked.
I create a new project and use a no-argument function to response Notification, it is worked normally.
The reason why I cannot receive the Notification is that a removeObserver method was called at one part which I didn't notice.
Thanks for all your reply.
for some reason this code isn't working in viewDidLoad, but will work in viewWillAppear. Any ideas?
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(wakeUp:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
Thank you
you're definitely sure viewDidLoad is being invoked?
For my case is that I put the removeObserver method inside didReceiveMemoryWarning method, and if I take a picture or do something else, this method fires out of my expect. So, now I always remove notification observer at dealloc stage.
Is it OK to use -removeObserver: first and then call -addObserver: with the same name? Or is it a rule to have -addObserver: first before -removeObserver:?
I tried it using OS 4.0 and it seems OK (no crash, warnings... etc.).
-(void) setObserver
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:OBSERVER_NAME object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector: #selector(selectorName)
name:OBSERVER_NAME
object:nil];
}
The reason is to prevent two observers with the same selectorName method being called twice assuming that -setObserver method was called again if its inside -viewDidLoad and a memory warning was issued.
Also, do I need to invoke -removeObserver: during -dealloc?
If you're getting -selectorName invoked twice, there's probably some other issue with your code. And even if Cocoa will be graceful about removing observers you haven't added yet, I wouldn't actually do that.
As user tonklon says in a comment, you should probably remove the observer in -viewDidUnload. As to your last question, it's also reasonable to remove the observer in -dealloc, though it's good practice to structure your code such that things like removing observers happen at a deterministic time rather than as a side-effect of memory management.