I am trying to pass NSString from one class to another. Let's say I have ViewController A and ViewController B. I want to pass NSString from A to B.
In ViewController A, I have following code :
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationMessageEvent" object:userType];
//Here user type is a string I get using delegate and I need to pass this userType to ViewController B
In ViewController B, I have following code :
In viewDidLoad , I have following code :
[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(notificationAction:) name:#"NotificationMessageEvent" object:nil];
//This NSNotificationCenter method is called
I have registered the following selector method.
-(void) notificationAction:(NSNotification *) notification
{
if ([notification.object isKindOfClass:[NSString class]])
{
NSString *message = [notification object];
// do stuff here with your message data
NSLog(#"%# is message",message);
}
else
{
NSLog(#"Error, object not recognised.");
}
}
//The above selector method is never called.
I have read other similar stackoverflow answers but I have not been able to find any solutions regarding this.
Your code and syntax is clearly correct. I'm guessing that it's a matter of object lifecycle. I would hypothesize that either of the following are true:
ViewController B doesn't actually exist as an object when the notification is posted
or
ViewController A is posting the notification before ViewController B has had a chance to register for it.
One way you can verify either of these is to add two breakpoints, one where the notification is posted, and one where the notification listener is registered. The breakpoint where the listener is registered should be hit before the notification is posted. If that happens, then verify that ViewController B is in fact an object in existence when the notification is posted (like it's not popped off the navigation stack or something).
This is what you are looking for
NSNotification not being sent when postNotificationName: called
You must addObserver before postNotificationName
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationAction:) name:#"NotificationMessageEvent" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationMessageEvent" object:nil];
Related
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.
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
I am very new to iOS development and I'm struggling to make an app which connects to BLE devices. As I have many view controllers I need to keep the peripheral always connected in all of them.
To achieve this, I implemented all the BLE connection methods in a Singleton. This works just great, I call the connect method from View Controller and the Singleton connects to the peripheral.
Now, the problem is I have a UILabel in my view controller which I would like to update with the connection state (scanning, connecting, connected, disconnected) from the Singleton.
So I tried to get instance from the View Controller and change the label directly like:
MainViewController *controller = [[MainViewController alloc] init];
controller.myLabel.text = #"TEST";
I also instantiated the view controller class like:
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle: nil];
MainViewController *controller = (MainViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"MainVC"];
Then I tried to create a method in the main View Controller:
- (void) updateLabel:(NSString *) labelText{
NSLog(#"CALLED IN MAIN");
self.myLabel.text = labelText;
}
And call it from Singleton like:
MainViewController *controller = [[MainViewController alloc] init];
[controller updateLabel:#"TEST"]
Which was called properly (NSLog was shown) but the label was not updated.
I don't really know how to update my View Controller label from the Singleton. Don't know neither if the way I'm trying to do it is the right one or not.
Any advice or help would be much appreciated. Thanks.
----- UPDATE: -----
Thanks to Mundi and Nikita, I got a better way to implement what I need through NSNotification. For all those who need it here is how I do it:
In my View Controller in viewDidLoad I call:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateConnectionLabel:) name:#"connectionLabelNotification" object:nil];
Then in the same class I implement the notification observer method like:
- (void)updateConnectionLabel:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"connectionLabelNotification"]) {
self.connectionLabel.text = notification.object; //The object is a NSString
}
}
Then in my Singleton, when I need I call:
[[NSNotificationCenter defaultCenter] postNotificationName:#"connectionLabelNotification" object:[NSString stringWithFormat:#"CONNECTED"]];
When the View Controller receives the notification from the Singleton it updates the label with the text I add on the notification object (in this case #"CONNECTED").
You need to use NSNotification.
Here is sample code:
in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mySelector:)
name:DeviceStateChanged
object:nil];
in dealloc:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:DeviceStateChanged
object:nil];
also add a method in ViewController:
- (void) mySelector:(NSNotification *) notification {
// action performed
}
in Sigleton
- (void) foo {
/// some actions
// device connected
[[NSNotificationCenter defaultCenter] postNotificationName:DeviceStateChanged object:self];
///
}
Recommendation: move notification name to your constants and use constant name. For naming convention look at Apple guidelines
The proper way to do this is via NSNotification. This communication device is meant for exactly this kind of situation. It broadcast a message without caring whether the potential receiver is available.
In your view controllers, you call NSNotificationCenter's addObserver / removeObserver when they appear / disappear. You post the notification via postNotification:.
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.
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...