didBecomeActive posts a notification, my view controller never hears it - ios

App delegate:
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[NSNotificationCenter defaultCenter] postNotificationName:APP_REFRESH_NOTIFICATION object:nil];
}
In my view controller:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doStuff) postNotificationName:APP_REFRESH_NOTIFICATION object:self];
}
- (void)doStuff never gets called. Why?

I assume that you've typed your question incorrectly and you'd meant to write addObserver:selector:name:object:, instead of addObserver:selector: postNotificationName:object: (such method doesn't exist).
In the documentation of - (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender
we can read:
notificationSender
The object whose notifications the observer wants
to receive; that is, only notifications sent by this sender are
delivered to the observer. If you pass nil, the notification center
doesn’t use a notification’s sender to decide whether to deliver it to
the observer.
So in your case, as you're passing object:nil in postNotificationName:object:, you also have to set object:nil in addObserver:selector:name:object:.
According to the documentation you also should replace the method doStuff with:
- (void)doStuff:(NSNotification *)notification
and use #selector(doStuff:) in addObserver:selector:name:object:.

You're passing self as the object parameter to addObserver:selector:name:object:, but doStuff doesn't accept any parameters, so the method call fails (silently). Your viewDidLoad should look like this:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doStuff)
name:APP_REFRESH_NOTIFICATION
object:nil];
}

You're app delegate is posting a notification when the app becomes active, but your view controller isn't subscribing to that until its view gets loaded. If your app delegate is creating your view controller and loading it (which is probable) then your controller doesn't even exist at the time the notification is posted, which is why it isn't receiving it. If you use a storyboard, and that controller is the entry point in the storyboard, AND you use the info.plist for your app to set that storyboard as the main interface, then it will have already instantiated the controller and loaded its view by the time -applicationDidBecomeActive: is called, solving your problem.

Related

Where should I put removeObserver from NSNotification

I have three viewControllers, and I'm trying to send a notification from viewController 3 to viewController 1 and 2. I think the best way to do this is to use NSNotification. Here's what I have so far:
In class C - Post the notification
[[NSNotificationCenter defaultCenter] postNotficationName:#"Updated "object:self];
In class B
In class A and B - Register first for the notification
// viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleUpdate:) name:#"Updated" object:nil];
-(void)handleUpdate:(NSNotification *)notification {
NSLog(#"recieved");
}
This works so far. But when I de-register it in class A and B:
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
The handleUpdate method doesn't get called. So the obvious problem is when I removeObserver's for the notification.
My question is, if everything I did so far is correct, why isn't it working when I remove the removeObserver? If it's not correct, where can I removeObserver's?
Everything you did is right. this is how the notification work.
If your class A,B always need to handle the update, you won't removeObserver.
Because you add your "addObserver" in viewDidLoad. it means you addObserver only once.
The normal error is that you add "addObserver" in "viewWillAppear" or "viewDidAppear", it will add more than once observer in the class. Then, you have to removeObserver in viewDidDisappear.

Save data from textField into a file when the application has closed or terminated

In my application has a view controller named "Home" with a textField.
I read about applicationDidEnterBackground and applicationWillTerminate methods in the AppDelegate file.
I know how to create, save, read data from a file.
My question is, How I can get an NSString from the "Home" viewController (that there store the textField data) to the AppDelegate applicationDidEnterBackground method and do there all my things with that data?
You could use NSNotificationCenter to register for a notification in your view controller that fires off whenever you enter applicationDidEnterBackground or applicationWillTerminate.
So in either of those methods you put something like
[[NSNotificationCenter defaultCenter] postNotificationName:#"someDescriptiveName" object:self userInfo:#{#"key" : #"value"}];
userInfo expects an NSDicitonary and you can pass it any type of object in there, in your case you dont need to pass anything from here back to your viewcontroller, your just using it as a means to let your view controller know the app is closing.
In your view controller you would register for that notification with something like this
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(methodToCall:) name:#"someDescriptiveName" object:nil];
Then whenever your appDelegate post that notification, your view controller which is registered to listen for it would fire off "methodToCall" which can be a method you right to do anything and it takes in an nsnotification which then lets you access the nsdicitonary its carrying.
- (void)methodToCall:(NSNotification *)notif{
NSLog(#"methodToCall fired with data %#",[[notif userInfo]valueForKey:#"key"]);}
You can do this with the help of this inside your controller:
-(id)init
{
if((self = [super init]))
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:[UIApplication sharedApplication]];
}
return self;
}
-(void)appDidEnterBackground:(NSNotification *)note {
NSLog(#"appDidEnterBackground");
}
you can also use applicationWillTerminate in place of UIApplicationDidEnterBackgroundNotification

Why is my NSNotification its observer called multiple times?

Within an App I make use of several viewcontrollers. On one viewcontroller an observer is initialized as follows:
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"MyNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethod:) name:#"MyNotification" object:nil];
Even when removing the NSNotification before initializing the number of executions of myMethod: is being summed up by the amount of repeated views on the respective viewcontroller.
Why does this happen and how can I avoid myMethod: being called more then once.
Note: I made sure by using breakpoints that I did not made mistakes on calling postNotification multiple times.
Edit: This is how my postNotification looks like
NSArray * objects = [NSArray arrayWithObjects:[NSNumber numberWithInt:number],someText, nil];
NSArray * keys = [NSArray arrayWithObjects:#"Number",#"Text", nil];
NSDictionary * userInfo = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification" object:self userInfo:userInfo];
edit: even after moving my subscribing to viewwillappear: I get the same result. myMethod: is called multiple times. (number of times i reload the viewcontroller).
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"MyNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethod:) name:#"MyNotification" object:nil];
}
edit: something seems wrong with my lifecycle. ViewDidUnload and dealloc are not getting called, however viewdiddisappear is getting called.
The way I push my Viewcontroller to the stack is as follows where parent is a tableview subclass (on clicking the row this viewcontroller is initiated:
detailScreen * screen = [[detailScreen alloc] initWithContentID:ID andFullContentArray:fullContentIndex andParent:parent];
[self.navigationController pushViewController:screen animated:YES];
Solution:
Moving removal of nsnotification to viewdiddisappear did the trick. Thanks for guidance!
Based on this description, a likely cause is that your viewcontrollers are over-retained and not released when you think they are. This is quite common even with ARC if things are over-retained. So, you think that you have only one instance of a given viewcontroller active, whereas you actually have several live instances, and they all listen to the notifications.
If I was in this situation, I would put a breakpoint in the viewcontroller’s dealloc method and make sure it is deallocated correctly, if that’s the intended design of your app.
In which methods did you register the observers?
Apple recommends that observers should be registered in viewWillAppear: and unregistered in viewWillDissapear:
Are you sure that you don't register the observer twice?
Ran into this issue in an application running swift. The application got the notification once when first launched. the notification increases the number of times you go into the background and come back. i.e
app launches one - add observer gets gets called once in view will appear or view did load - notification is called once
app goes into background and comes back, add observer gets called again in view will appear or view did load. notification gets called twice.
the number increases the number of times you go into background and come back.
code in view will disappear will make no difference as the view is still in the window stack and has not been removed from it.
solution:
observe application will resign active in your view controller:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationWillResign:", name: UIApplicationWillResignActiveNotification, object: nil)
func applicationWillResign(notification : NSNotification) {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
this will make sure that your view controller will remove the observer for the notification when the view goes into background.
it is quite possible you are subscribing to the notifications
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification" object:self userInfo:userInfo];
before self gets initialized. And trying to unsubscribe 'self' which isn't really subscribed to, and you will get all global myNotification notifications.
If your view was hooked up in IB, use -awakeFromNib: as the starting point to register for notifications
It is possible that the class with the observer is, quite appropriately, instantiated multiple times. When you are debugging it will kinda look like the notification is being posted multiple times. But if you inspect self you might see that each time is for a different instance.
This could easily be the case if your app uses a tab bar and the observer is in a base class of which your view controllers are subclasses.

Knowing the app. launc in Objective C

The app. delegate has the method that gets invoked when the app launches. Pain is my app is not following MVC and I have to reset many text fields to empty when the app. launches(not concerned about first launch). These txt fields are not created in app delegate so i cannot set them in app delegate (as the txt fields are not accessible). how can i know the app has launched in the new class to reset the fields . Is there any condition like
if(application.HasAppLaunced)
{
}
KIndly help
You could register your view controller as an observer of event
UIApplicationDidEnterBackgroundNotification
or
UIApplicationWillEnterForegroundNotification
in your view controller somewhere in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appEnteredBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
and add this method to reset your fields, you can reset all fields here:
- (void)appEnteredBackground{
[textField setText:#""];
}
don't forget to unregister your view controller, put this in some appropriate location:
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
I don't completely understand what are you asking for, but if the question is how to detect whather app is active you may use following condition:
[[UIAppication sharedApplication] applicationState] == UIAppicationStateActive
Try This
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Reset your text fields here
}
Try this one.. You can call a method to empty thetextfields using NSNotificationCenter
You can write the following line in AppDelegate.
[[NSNotificationCenter defaultCenter]postNotificationName:#"EmptyFields" object:nil];
You can write the following line in viewDidLoad method.
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(setEmpty) name:#"EmptyFields" object:nil];
You can do textfields empty in the following method. You can write it in your ViewController.
- (void) setEmpty{
NSLog(#"Empty....");
}

Notification Observer is not catching the post

I have a split view controller, and the child masterView is attempting to send out a post notification under certain conditions in the 'viewDidAppear' method. However, the Observer that is located in the parent isn't ever being triggered.
Here is the observer code, implemented inside the viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(customerSearchStatusIsSelected:) name:#"CUSTOMER_ORDER_DID_CHANGE_NOTIFICATION" object:nil];
and this is the post I have in the child masterView's viewDidAppear:
[[NSNotificationCenter defaultCenter] postNotificationName:#"CUSTOMER_ORDER_DID_CHANGE_NOTIFICATION" object:nil userInfo:[NSDictionary dictionaryWithObject:_tableData forKey:#"data"]];
this is my selector method header
-(void)customerSearchStatusIsSelected:(NSNotification *)data
{
//some code
}
The childMasterView definitely sends out the post, but the selector I want the observer to call never gets called. What exactly am I missing here?
solution: needed to move the observer from viewDidLoad to viewDidAppear ... for whatever reason...

Resources