I want to send an NSNotification from this method (when the UIButton is clicked) in my AppDelegate.m:
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0){
//cancel clicked ...do your action
// HERE
}
}
..and receive it in one of my UIViewControllers. How can I do that?
EDIT WITH MORE INFO: I am making an alarm app, and when the user presses the UIButton, I want to stop the alarm. I figured that NSNotifications is the only way to get information from my AppDelegate.m file to a ViewController.m file?
You should to register your receiver object to accept some messages sent from Notification Center.
Suppose you have Obj A which controls your alarm, and value "stopAlarm" is the message which can stop alarm. You should create an observer for a "stopAlarm" message.
You can do, with:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(controller:)
name:#"stopAlarm"
object:nil];
Now, you should create a method controller that manages this messages:
- (void)controller:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"stopAlarm"]){
//Perform stop alarm with A object
}
}
Finally, you can send the message "stopAlarm" when you want in the code with:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"stopAlarm"
object:nil];
I Hope this may help.
EDIT:
When your UIViewController are unloaded or when app terminate, you should call:
[[NSNotificationCenter defaultCenter] removeObserver:self];
for stop observing.
That's all.
Thanks to Hot licks for correction.
You may want to create a class–maybe even a singleton if there is only one alarm–that manages the timer. That way you can manage from any place in your application rather than in the view controller. Take a look at:
http://dadabeatnik.wordpress.com/2013/07/28/objective-c-singletons-an-alternative-pattern/
and:
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Notifications/Articles/NotificationCenters.html
As Hot Licks mentioned, you really do not want to jump into this without knowing what is going on. Hopefully these links will help get you going in the right direction.
Related
I am fairly new to iOS dev. I have been trying to find an answer to this but don't have a definite solution..
I have a view called FirstView.m
And there's AppDelegate.m
A background task is running in AppDelegate.m which updates a variable called `text' depending upon the closest beacon to the phone.
When the app is in FirstView, I want to update a UILabel inside FirstView as per the variable text of AppDelegate.
I know this can be done by running a background thread in FirstView which every 1 second checks whether the variable in AppDelegate was changed or not, but this doesn't seem efficient to me at all, there is no point running two background threads for the same task.
My questions is, is there a way to update the label from AppDelegate itself ? Something on the lines of performSelectorOnMainThread ?
Thanks!
You could post a notification with the text in the userInfo dictionary in the AppDelegate anytime that value changes:
text = [iBeacon updateText]; // just a random method name I made up
[[NSNotificationCenter defaultCenter] postNotificationName:#"textChanged"
object:self
userInfo:#{#"text":text}];
Then in the FirstView you can listen for that notification to update the UI (normally in viewDidLoad or in viewDidAppear:). Be sure to unregister before the view controller is dealloced somewhere in FirstView so there are no memory leaks. Example for registering and updating UI
You can register like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleTextChanged:)
name:#"textChanged"
object:nil];
Then update the UI:
- (void)handleTextChanged:(NSNotification *)notification
{
// Be sure to update the UI on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
self.label.text = notification.userInfo[#"text"];
});
}
And finally, unregister for notifications:
[[NSNotificationCenter defaultCenter] removeObserver:self];
One more way you can try the same using keyValue Observing. Refer this Apple Documentation and how to implement the same.
I have referred the following links for this issue, but neither of the solutions worked for me:
Link 1
Link 2
I think these solutions don't work for iOS7.
So now how would I be able to find out whether there is any UIAlertView open, when my application enters in background state.
I want to dismiss the UIAlertView before going into the background.
Remove alert in applicationDidEnterBackground
Add this line in your class
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(enteredBackground:)
name:UIApplicationDidEnterBackgroundNotification
object: nil];
And implement method as well
- (void)enteredBackground:(UIApplication *)application
{
if (mainAlertView && mainAlertView.isVisible)
[mainAlertView dismissWithClickedButtonIndex:0 animated:NO];
}
You get a notification when the app is send to background, so detect that notification in the class that displays the alert view and remove it, that's all
have you checked UIAlertView property #property(nonatomic, readonly, getter=isVisible) BOOL visible Also while going in the background you get a notification in - (void )applicationDidEnterBackground: you can check there and remove all alertviews if any
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.
I'm developing an app which has to communicate with an external accessory. The app has several requests to send to the external accessory.
My problem:
I'm using observers in different places (classes), I'm adding the following observers in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(observer1:)
name:EADSessionDataReceivedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(observer2:)
name:EADSessionDataReceivedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(observer3:)
name:EADSessionDataReceivedNotification object:nil];
The 1st Observer works very well, but I'm getting problems with the other two. They don't respond until the first one has been used. Do I need to add something else?
The flow is as follows:
Send a request to ext-acc and fire a flag to know which observer will take the returned data
ext-acc responds with data
The receiver method pushes a notification into notification center.
The observer with the flag in 1 will take the data (at this point do I need to remove the notification since no one else will need it?).
Looks you have a misunderstanding regarding how NSNotificationCenter works. You are registering your object (self) to observe the notification EADSessionDataReceivedNotification three times, each with it's own selector (observer1, observer2, observer3).
So, what is happening is correct for your code as written. When EADSessionDataReceivedNotification is posted, NSNotificationCenter sends the specified selector to each observer. There is no conditional logic or way to cancel a notification.
Given your description, it sounds like you should only be observing the notification once and checking your flag to determine how to process. Something like:
// observe notificaton
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dataReceived:) object:nil];
// notification handler
- (void)dataReceived:(NSNotification *)notification {
if (someCondition) {
[self handleDataCondition1];
}
else if (aSecondCondition) {
[self handleDataCondition2];
}
else if (aThirdCondition) {
[self handleDataCondition3];
}
else {
// ????
}
}
Last week I asked this question: Refresh the entire iOS app
#Jim advised me to use the notification center. I was not able to figure out how to work with notifications and I was told to ask another question, I tried for the full week to figure it out on my own, so here goes.
I have a view with multiple subviews. One of the subviews is a search bar (not the tableview one, just a custom text box), the user can search for a new person here and the entire app will be updated screen by screen.
When the user taps on the GO button in the search subview I make the call to the server to get all the data. After which I post this notification:
[self makeServerCalls];
[[NSNotificationCenter defaultCenter] postNotificationName:#"New data" object:Nil];
Now in the init of my parent view controller I have a listener
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewDidLoad) name:#"New data" object:nil];
I know this is most probably wrong, so can anyone explain to me how to use notifications properly in my situation? Or if there is a better way of doing what I want.
Thanks for any help you can give me.
When you post a notification, it will cause all register observers to be notified. They get notified by having a message sent to them... the one identified by the selector. As mentioned in the comments, you should not use viewDidLoad. Consider this...
- (void)newDataNotification:(NSNotification *notification) {
// Do whatever you want to do when new data has arrived.
}
In some early code (viewDidLoad is a good candidate):
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(newDataNotification:)
name:#"New data"
object:nil];
That's a terrible name, BTW. Oh well. This registration says that your self object will be sent the message newDataNotification: with a NSNotification object whenever a notification is posted with the name "New data" from any object. If you want to limit which object you want to receive the message from, provide a non-nil value.
Now, when you send the notification, you can do so simply, like you did in your code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"New data" object:nil];
and that will make sure (for practical purposes) that [self newDataNotification:notification] is called. Now, you can send data along with the notification as well. So, let's say that the new data is represented by newDataObject. Since you accept notifications from any object, you could:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"New data"
object:newDataObject];
and then in your handler:
- (void)newDataNotification:(NSNotification *notification) {
// Do whatever you want to do when new data has arrived.
// The new data is stored in the notification object
NewData *newDataObject = notification.object;
}
Or, you could pass the data in the user info dictionary.
[[NSNotificationCenter defaultCenter]
postNotificationName:#"New data"
object:nil
userInfo:#{
someKey : someData,
anotherKey : moreData,
}];
Then, your handler would look like this...
- (void)newDataNotification:(NSNotification *notification) {
// Do whatever you want to do when new data has arrived.
// The new data is stored in the notification user info
NSDictionary *newData = notification.userInfo;
}
Of course, you could do the same thing with the block API, which I prefer.
Anyway, note that you must remove your observer. If you have a viewDidUnload you should put it in there. In addition, make sure it goes in the dealloc as well:
- (void)dealloc {
// This will remove this object from all notifications
[[NSNotificationCenter defaultCenter] removeObserver:self];
}