i'm new in IOS. i look for solution for over a day but all available solution work within a single UIViewConntroller but when i did it between uiTableView row selection and UIViewConntroller as Observer then the Selector is not called by Observer.
On row Selection in uitableviewcontroller
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
NSNotification * notification =[[ NSNotification alloc] initWithName:#"NOTIFICATION" object:nil userInfo:dict];
**In UIViewController on viewdidload **
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedNotification:)
name:#"NOTIFICATION" object:nil];
**SelectorAction in uiviewcontroller **
-(void) receivedNotification:(NSNotification*) notification
{
NSLog(#"Notification Received ");
}
hi #Abdul Rehman Warraich, i got your problem. you are posting notification in one view, and trying to observe it an another view. but what happens is, in the second view your observer is not ready (not loaded) to get the notification what you sent.
once you landed in the second view, that time itself observer is loaded.so it obviously will miss the notification.
so whenever you do push and pop, observer will loading as new one. so every time it will fail to observe it.
HINT: Try to load observer in your second view , before you fire the notification.
Hope it will help you to debug.
You don't have to creat a NSNotification object. Just post the notification when row selected :
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:nil userInfo:dict];
In UITableViewController when you select the row Post Notification:
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:nil userInfo:dict];
In UIViewController viewDidLoad method addObserver:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedNotification:)
name:#"NOTIFICATION" object:nil];
Write method in UIViewController:
-(void)receivedNotification:(NSNotification*) notification
{
NSLog(#"Notification Received ");
}
Check if UIViewController's instance is there in the stack? otherwise you will not get the response.
There is no problem in any of the above code infect i'm doing it in wrong way. I'm posing notification first and observing after posting notification.
But i have to observe first and post notification after it.
I solve this problem as :
In AppDelegate didFinishLaunchingWithOptions: load viewControler first so that the observer is ready to get notification(inViewDidLoad) and after that Show/navigate to tableView And then it work perfect.This isn't the proper way but work for me. :)
Also Read out the #karthik and #Priyanka Mistry Answers. Helped me to solve the problem.
Use tableView didSelectRowAtIndexPath Delegate:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
//Post notification here
}
Stefos' answer is the usual way to post a notification, but if you do want to create a notification object manually, you then need to post it:
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
NSNotification * notification =[[ NSNotification alloc]
initWithName:#"NOTIFICATION"
object:nil userInfo:dict];
[[NSNotificationCenter defaultCenter] postNotification: notification];
(I don't think I've ever done it in 2 steps like this. I always use one of the forms that takes a name, option, and userInfo and creates and posts the notification in one call.)
Try this i hope it would be helpful:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
myData = [[NSMutableArray alloc]init];
myData = [[NSMutableArray alloc]initWithObjects:#"india",#"Japan",#"pakistan",#"srilanka", nil];
_mytableView.delegate = self;
_mytableView.dataSource = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:)name:#"NOTIFICATION" object:nil];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return myData.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *const identifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.textLabel.text = [myData objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:nil userInfo:dict];
}
-(void) receivedNotification:(NSNotification*) notification {
NSLog(#"Notification Received ");
}
#end
in viewcontroller.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray *myData;
}
#property (weak, nonatomic) IBOutlet UITableView *mytableView;
#end
Related
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"];
}
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);
}
I have a TableView setup in the storyboard and have a prototype cell that I use to hold images and a button to start videos. The path of the video file is a property in each cell object and I would like to play the video when the button is clicked.
Before I began using the table (when I just had button manually drawn on the storyboard) i used the follow to start the movie player [self presentMoviePlayerViewControllerAnimated:mp]; but obviously now that's not possible.
I'm sure I'm missing something obvious...
The best solution for this is NSNotificationCenter. On Click, in your Cell just send notification with index of your row that you can save in button's tag variable.
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:#"playVideo" forKey:#"operationKey"];
[userInfo setValue: indexPath forKey:#"indexPathRow"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"PlayVideoNotification" object:nil userInfo:userInfo];
In your ViewController register observer:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivePlayVideoNotification:) name:#"PlayVideoNotification" object:nil];
And do not forget unregister observer:
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"PlayVideoNotification" object:nil];
In the method PlayVideoNotification do what you need:
- (void) receivePlayVideoNotification:(NSNotification *) notification
{
NSDictionary *userInfo = notification.userInfo;
NSString *operationKey = [userInfo objectForKey:#"operationKey"];//"playVideo"
NSString* indexPathRow = [userInfo objectForKey:#"indexPathRow"];
//todo
}
I think you should use custom cell to achieve your objective.
You can follow these steps:
Create a new class that is a subclass of UITableViewCell and assign it as the class of your custom cell.
In your custom class .h file make an IBOutlet for your button.
In your main class .m file use this method to play video
- (void)playBtnClicked:(id)sender {
MPMoviePlayerViewController *movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:YourURL];
[self presentMoviePlayerViewControllerAnimated:movieController];
[movieController.moviePlayer play];
}
Use this code after you have configured your cell
[cell.btn_PlayVideo addTarget:self action:#selector(playBtnClicked:) forControlEvents:(UIControlEventTouchUpInside)];
Your should make sure that MediaPlayer.framework is included and MediaPlayer.h file is imported.
As far as I know you have to segue to another ViewController and start the moviePlayerViewController there.
I think you can't just get the IBAction when you click on a TableViewCell.
So try to segue in the InterFaceBuilder, build a ViewController with something like this:
ViewController.h:
#interface ViewController : UIViewController
#property (nonatomic, strong) NSURL *videoFileUrl;
#end
ViewController.m:
#implementation ViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
...
[self presentMoviePlayerViewControllerAnimated:mp];
}
#end
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
I am using push notifications in my code and whenever a notification comes, I want to update the value of a label in another ViewController.
My code in AppDelegate is:
- (void)addMessageFromRemoteNotification:(NSDictionary*)userInfo updateUI:(BOOL)updateUI
{
NSLog(#"Notification arrived");
//[mydeals setCode1_id:mydeals.code1_id withString:#"123456"];
mydeals=[[MyDealsViewController alloc]init];
NSDictionary* codeDetails=[[NSDictionary alloc] initWithObjectsAndKeys:#"123456",#"Code_id", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CodeArrived" object:self userInfo:codeDetails];
}
then in my other view controller I have this code:
#implementation MyDealsViewController
-(id) init
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveCode:)
name:#"CodeArrived"
object:nil];
return self;
}
-(void) receiveCode:(NSNotification*)notification
{
NSLog(#"received Code: %#",notification.userInfo);
self.code1_id.text=[NSString stringWithFormat:#"%#",[[notification userInfo] valueForKey:#"Code_id"]];
}
the log is printed correctly but when I manually go into that screen I see the default value, like the label is not updated at all. What should I do?
You have to make sure that when you "manually go" to MyDealsViewController, whatever how you do it, it got to be the same instance of MyDealsViewController wich has been called receiveCode. Otherwise it's going to init with it's default values.
You might also try calling [self.code1_id setNeedsLayout];