How to send & receive data using NSNotificationCenter in iOS (XCode6.4) - ios

I am facing an issue with NSNotificationCenter.
I am not able to send message and receive message using NSNotificationCenter in latest ios 8.4 (XCode 6.4)
Please check the following code:
1) I want to send data using first view controller to another view.
so i have written the following code in first viewcontroller:
When user btn clicked method as following :
- (IBAction)btnClicked:(id)sender
{
[self postNotification];
[self performSegueWithIdentifier:#"asGo" sender:self];
}
-(void)postNotification{
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:self];
}
2) In Second view controller i have added observer in ViewWillApper as following :
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(eventListenerDidReceiveNotification:)
name:#"MyNotification"
object:nil];
}
-(void)eventListenerDidReceiveNotification:(NSNotification*)txt
{
NSLog(#"i got notfication:");
}
so eventListenerDidReceiveNotification is not called while come on view.
But i am not getting above log while i come on second vc with navigation

As others have noted, NSNotificationCenter doesn't work like a post office. It only delivers notifications if someone actually listens to them at the moment they arrived. This is the reason your eventListenerDidReceiveNotification method is not being called: you add an observer in viewWillAppear, which is called after the segue (I assume that you're using segues because of the performSegueWithIdentifier method in your code) is finished, so it's definitely called after postNotification has been called.
So, in order to pass data via NSNotificationCenter you have to add an observer before you post a notification.
The following code is completely useless and unnecessarily overcomplicated, you shouldn't do anything like that, but since you keep insisting on using a scheme like this, here you go:
//Didn't test this code. Didn't even compile it, to be honest, but it should be enough to get the idea.
NSString * const SOUselessNotificationName = #"MyUselessNotification";
#pragma mark - FIRST VC
#interface SOFirstVC : UIViewController
#end
#implementation SOFirstVC
NSString * const SOasGoSegueIdentifer = #"asGo";
- (IBAction)btnClicked:(id)sender {
[self performSegueWithIdentifier:SOasGoSegueIdentifer sender:self];
}
-(void)postNotification {
[[NSNotificationCenter defaultCenter] postNotificationName:SOUselessNotificationName object:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifer isEqualToString:SOasGoSegueIdentifer]) {
SOSecondVC *destinationVC = (SOSecondVC *)segue.destinationViewController;
[destinationVC registerToReceiveNotificationsFromObject:self];
[self postNotification];
}
}
#end
#pragma mark - SECOND VC
#interface SOSecondVC : UIViewController
-(void)registerToReceiveNotificationsFromObject:(id)object;
#end
#implementation SOSecondVC
-(void)registerToReceiveNotificationsFromObject:(id)object {
[[NSNotificationCenter defaultCenter] addObserver:self selector:(eventListenerDidReceiveUselessNotification:) name:SOUselessNotificationName object:object];
}
-(void)eventListenerDidReceiveUselessNotification:(NSNotification*)uselessNotification {
NSLog(#"I got a useless notfication! Yay!");
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#end

NSNotificationCenter basically has 3 steps
Adding Observer like [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(open:) name:#"OpenDetail" object:nil];
Posting Notification [[NSNotificationCenter defaultCenter] postNotificationName:#"OpenDetail" object:self];
Removing Observer [[NSNotificationCenter defaultCenter] removeObserver:self name:#"OpenDetail" object:nil];
I think you are posting your notification and then later adding observer while it's vie versa. You have to add observer first then post notification.
HTH

First you have to setup the data you want to send
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:#"aKey"];
Then you post it with the data like so:
[[NSNotificationCenter defaultCenter] postNotificationName: #"MyNotification" object:nil userInfo:userInfo];
And finally you read the data off the notification:
-(void)eventListenerDidReceiveNotification:(NSNotification*)notification
{
NSLog(#"i got notification:");
NSDictionary *userInfo = notification.userInfo;
NSString *myObject = [userInfo objectForKey:#"aKey"];
}

Related

The NSNotificationCenter is never executed

This is my code.
Here create the observer to Notification called Example into ViewController
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
}
From viewDidLoad register my observer
- (void)viewDidLoad
{
[self addObserverExample];
}
In my second ViewController. When tapped a button excute this code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:self.dictKeys userInfo:nil];
The problem I have is that the notification is never executed.
Any idea.
Have created demo for NSNotificationCenter as per your question and it's working fine for me. Here it is the link of that code: NSNotificationCenter Demo
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserverExample];
}
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
NSLog(#"%#",notification.userInfo);
}
- (IBAction)btnFireNotification:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:nil userInfo:#{#"key" : #"value"}];
}
I believe the problem you're having may be related to the fact that in your second view controller, you're passing self.dictKeys in the object parameter.
If you want to pass data via the NSNotificationCenter, you should use the userInfo parameter instead.
Darshan's example does this the correct way.

Populate data in textfield from button action of another class

my problem is that i have a textfield on my viewcontroller which should be get filled by user and to provide options to fill the textfiled there is a arrow button front of textfield. Clicking on it open a new viewcontroller with a list of options. So when the user click on any option from that viewcontroller the data will automatically fill in that textfield and user return on previous viewcontroller. And i can not use preprefor segue in it so please provide an answer. If i am missing something let me know i ll comment or edit.
You can use NSNotificationCenter to fill back your UITextField. Add Observer to your first viewController class where you want to fill the textField. Add this lines of code in viewDidLoad-
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fillMyTextField:) name:#"fillMyTextField" object:nil];
than add selector method in same class--
- (void)fillMyTextField:(NSNotification *)notification
{
self.myTxtField.text = (NSString *)notification.userInfo;
}
Now in your other viewController class where you select data for textField. Write the below code in method where you select your data like-
- (IBAction)selectDataAndBackToPreviosVC:(UIButton*)selectedOptionBtn {
id object=[NSString stringWithFormat:#"%#",selectedOptionBtn.titleLabel.text];
[[NSNotificationCenter defaultCenter] postNotificationName:#"fillTextField" object:nil userInfo:object];
[self.navigationController popViewControllerAnimated:YES];
}
in this I have used navigationViewController which use Push and Pop viewControllers and i have some UIButton in option selection viewController. I'm passing button title which is options to myTextField on IBAction.
In class where textfield Define Below method (add notification observer)
in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fillTextField:)
name:#"fillTextField"
object:nil];
- (IBAction)fillTextField:(NSNotification *)sender
{
textField.text = (NSString *)notification.object
}
In Another class where u select date set below method in date selection action
[[NSNotificationCenter defaultCenter] postNotificationName:#"fillTextField" object:nil userInfo:textFieldInfo];
You can use NSNotification:
In View controller ofTextField add this
- (void) viewDidLoad
{
//Your rest of code then below statement
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTextNotification:)
name:#"TestNotification"
object:nil];
}
- (void)receiveTextNotification:(NSNotification *)notification {
NSLog(#"%# updated", [notification userInfo]);
}
- (void) dealloc
{
// If you don't remove yourself as an observer, the Notification Center
// will continue to try and send notification objects to the deallocated
// object.
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
In View controller of Button, on button click add this:
- (IBAction)fillTextFieldAction: (id) sender {
// All instances observing the `TestNotification` will be notified
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:self userInfo:text]; //Object here can be any changed value .
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fillTextFieldAction:) name:#"fillTextField" object:nil];
- (IBAction)fillTextFieldAction:(NSNotification *)notification
{
textField.text = (NSString *)notification.object
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"fillTextField" object:nil userInfo:textFieldInfo];

Calling UIWebView from different class

I have ViewController1.m and ViewController2.m
In ViewController1.m I have a UIWebView and also I created a method to load a URL.
If I call that method from ViewController1.m it works.
But when I try to call that method from ViewController2.m I does not work.
I realised that it is because I creating a new instance of ViewController1.m Class.
So my question is, how can I call that method but for the active instance of the ViewController1 Class?
Best Regards,
I was able to do what I need it to do by using Notifications.
I dont know if this is the best way of doing it by it worked for me.
I hope this could be useful to someone else.
In ViewController1.m
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
}
- (void) receiveTestNotification:(NSNotification *) notification
{
[YourWebView stringByEvaluatingJavaScriptFromString:#"alert('It works');"];
}
In ViewController2.m
-(void) someMethod {
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];
[self dismissViewControllerAnimated:YES completion:nil];
}

Pass NSString values from one ViewController to Another using Notifications?

How can I pass NSString values from ViewController1 to ViewController2 by using notifications in iOS? I have tried:
ViewController1
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"test" object:nil];
}
- (void) incomingNotification:(NSNotification *)notification{
NSString *theString = [notification object];
NSLog(#"theString value=%#",theString);
}
ViewController2
- (void)viewDidLoad
{
NSString *myString=#"testing";
[[NSNotificationCenter defaultCenter] postNotificationName:#"test" object: myString];
}
It works fine while am going to ViewController2.
But I want to send values from ViewController1 to ViewController2 using these notifications. Is it possible. How?
You can use it by initializing ViewController2 in ViewController1's on button click event..Steps to invoke,
1.Create on method (say like notifRegister) in ViewController2,which initialize notification to receive dictionary value.
2.On button click event init ViewController2 and call method notifRegister
3.Then post notification in ViewController1.
Example:
- (IBAction)navigation:(id)sender {
ViewController1 *vc= [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController2"];
[vc notifRegister];
[self.navigationController pushViewController:(UIViewController*)vc animated:YES];
NSDictionary *name=[[NSDictionary alloc] initWithObjectsAndKeys:#"Tommy",#"name",nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"TextChanged" object:name];
}
On ViewController2:
-(void)notifRegister
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reloadLabel:) name:#"TextChanged"object:nil];
}
-(void)reloadLabel:(NSNotification*)sender
{
NSLog(#"reload label called %#",sender.object);
self.labelName=[sender.object objectForKey:#"name"];
}
Here self.labelName is an NSString object...
I think it is not necessary to call a invisible viewController to send notification. You can pass your values as below:
If you use storyboard, you can get ViewController2 in ViewController1's method prepareForSegue, so you can pass your reference here.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var targetViewController = segue.destinationViewController as UIViewController
}
If your manually create the second ViewController and use presentViewController, just pass your reference when initializing your ViewController2.
If you insist to use notification. Set view2 as a notification sender and view1 as a receiver with another notification.
You get an NSNotification object passed to your function.
Put your strings or other objects in the dictionary
NSDictionary* userInfo = #{#"completionHandler" : completionHandler,
#"myStringIdentifier" : myString};
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:#"myNotification" object:self userInfo:userInfo];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:) name:#"UIKeyboardWillHideNotification" object:nil];
-(void) receiveNotification:(NSNotification*)notification
{
if ([notification.name isEqualToString:#"MyNotification"])
{
NSDictionary* userInfo = notification.userInfo;
... do dictionary stuff
}
}
This is a question which has been asked before search for userinfo and NSNotification for more examples
As per the doc, yes it's possible. But you should read the doc first (see NSNotificationCenter class reference).
The method you should look at is
- (void)postNotificationName:(NSString *)notificationName
object:(id)notificationSender
userInfo:(NSDictionary *)userInfo
where
notificationName is the notification you want to post. The notificationSender is the object that want to post the notification and userInfo is the info you want to pass with the notification.
So, if you want to pass a notification from ViewController2 to ViewController1 (or viceversa).
// ViewController1
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"myNotificationName" object:nil];
}
- (void) incomingNotification:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSString *theString = userInfo[#"stringKey"]; // Here you retrieve the passed string from ViewController2 to ViewController1
NSLog(#"%#",theString);
}
// ViewController2
// Suppose you have an action set up for a specific button
- (IBAction)buttonTapped {
NSDictionary *userInfo = #{#"stringKey": #"stringPassed"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotificationName" object:self userInfo:userInfo];
}
Here I would highlight two main things.
Both controllers should be "valid". In other words they should be allocated in memory and presented somewhere.
When you add an observer you should also remove it.
Update 1
In this case you are passing a string from UIViewController2 to UIViewController1. Just switch the code you are using and you will be able to pass the same string from ViewController1 to ViewController2.
My question: what's your goal?
this will work...
in ViewController 2
[[NSNotificationCenter defaultCenter] postNotificationName:#"test" object:self userInfo:#{#"stringValue": myString}];
in ViewController 1
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"test" object:nil];
}
- (void) incomingNotification:(NSNotification *)notification{
NSString *theString = notification.userInfo[#"stringValue"] ;
NSLog(#"theString value=%#",theString);
}

NSNotificationCenter , prints memory address

I have in my app a UITableview Controller, a View Controller and I'm trying to pass NSDictionary from UITableview Controller to my ViewController, using NSNotificationCenter. So, I push a notification at my UITableview Controller and then I add an observer ,using a selector at my ViewController.The selector is called,but I have an NSLog and get memory results ,like :
ViewController: 0x8a0bcc0
I have tried to pass NSString instead of NSDictionary , but I get again memory results , and not the value of the string.
My code :
UITableView Controller
NSString *string=#"This is a test string";
[[NSNotificationCenter defaultCenter] postNotificationName: #"Update" object: string];
ViewController
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"Update" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self];
And here is the incomingNotification selector method:
-(void) incomingNotification : (NSNotification *)notification{
NSLog(#"Trying to print : %#",[notification object]);
}
All Notifications take place at ViewDidLoad method.Thank you!
UPDATE
Finally , I quit using NSNotificationCenter and used properties to pass data ,changing a bit the inheretence from my TableViewController. No idea why Notifications did not work ,as they were supposed to. Thank you all ,very much for your suggestions and ideas :)
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self]
Object means the object that generates a notification. To post parameters use another method
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self userInfo:string]
If I understand correctly, UIViewController is shown after you tap a button on UITableViewController. And you if you are adding a ViewController as observer in its -viewDidLoad:, then it will be able to receive notifications only when it is loaded.
What do you need:
1) override -init or -initWithNibName: method of ViewController like this:
-(id) init
{
self = [super init];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"Update" object:nil];
}
return self;
}
so you can be sure ViewController is observing for notifications from the beginning (well, this might be unnecessary step for your case)
2) when you push ViewController you need to send a notification after it was created, like this:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ViewController *nextController = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:nextController animated:YES];
NSString *string=#"This is a test string";
[[NSNotificationCenter defaultCenter] postNotificationName: #"Update" object: string];
}
However, if you're trying just to send some parameters from one view controller to another, this is the wrong way. Just create a property in ViewController and in method -tableView:didSelectRowAtIndex: of UITableViewController set this property

Resources