I have two classes. A and B for example.
I have created an observer in A like this
- (void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(somethingHappens:) name:#"notificationName" object:nil];
}
-(void)somethingHappens:(NSNotification*)notification
{
NavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"contentViewController"];
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"loyaltyVC"];
navigationController.viewControllers = #[vc];
}
I want to call this observe from page B. I'm using like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"notificationName" object:self];
Do you have any suggestion how we can do this ?
To be precise this are not push notifications. The following are just normal in-app-notifications.
Your -(void)viewDidLoad should contain a call to its super method at some point.
//in A
#implementation AThingy {
id<NSObject> observeKeeper;
}
- (void)viewDidLoad {
[super viewDidLoad];
observeKeeper = [[NSNotificationCenter defaultCenter] addObserverForName:#"notificationName" object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {
UINavigationController *nav = [self.storyboard instantiateViewControllerWithIdentifier:#"contentViewController"];
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"loyaltyVC"];
nav.viewControllers = #[vc];
}];
}
// not mandatory but to explain it complete
-(void)dealloc {
// could be placed in some other method also.. like -viewDidDisappear:
[[NSNotificationCenter defaultCenter] removeObserver:observeKeeper];
}
#end
//in B
#implementation BThingy
-(void)postNotify {
[[NSNotificationCenter defaultCenter] postNotificationName:#"notificationName" object:nil];
}
#end
But keep in mind that NotificationCenter is working relative to its observing Objects and so it matters if you watch and post in general on (nil) or on some specific object. Why is that? Because you could decide to instantiate two objects from the same class that observe notifications and still specifically observe each notification meant for them or both.
Have you tried to print a log in method somethingHappens:?
Is your method -(void)didLoad ever been called?
Related
I have three view controllers, say root, middle, last. I want to go back from lastViewController to rootViewController.
I tried custom delegate and NSNotificationCenter. But while going back the middleViewController flashes for a second (it's viewWillDisappear gets called).
I'm using presentViewController/dismissViewController and not navigation. I don't want that middleViewController getting flashed.
I have below code in rootViewCotroller:
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(actionBackToRoot) name:#"BackToRoot" object:nil];
}
-(void)actionBackToRoot : (NSNotification *) notification{
NSDictionary *userInfo = notification.userInfo;
UIViewController *lastViewController = [userInfo objectForKey:#"viewController"];
[middleViewController dismissViewControllerAnimated:NO completion:nil];
[lastViewController dismissViewControllerAnimated:NO completion:nil];
}
On click of close button of lastViewController, code as below -
[dict setValue:self forKey:#"viewController"];
[[NSNotificationCenter defaultCenter]postNotificationName:#"BackToRoot" object:nil userInfo:dict];
Does anyone have solution for this?
Thanks in advance.
Did you tried lastViewController.navigationController.popToRootViewController(animated: true )
I have main viewcontroller that opens via popover segue other view controller with buttons.
On button click what I wish to happen is function from first viewcontroller fire and the popover will close. How do I do so properly?
On settings button click the popover open. Then when user click Manual Content Update the the view will close and start function on Projects Main viewController.
You can use NSNotificationCenter.
In your main UIViewController add:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivePopoverNotification:)
name:#"PopoverNotification"
object:nil];
}
-(void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void) receivePopoverNotification:(NSNotification *) notification
{
[self.popover dismissPopoverAnimated: YES];
self.popover = nil;
}
In your UIPopoverController add:
-(IBAction) pressButton: (id) sender {
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PopoverNotification"
object:nil];
}
In my app, UITabBarController is an initial ViewController build in storyBoard. I would like to observe data updating in my whole app. So I add an observer in appDelegate...
AppDelegate.m
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(shipCountBadge:) name:kShipCountBadge object:nil];
- (void)shipCountBadge:(NSNotification *)notification{
Groups *vc = [[Groups alloc] init];
[vc addBadgeCount:notification.object];
}
Group.m
- (void)addBadgeCount:(NSNumber *)count{
NSLog(#"d",[count intValue]);
[[self.tabBarController.tabBar.items objectAtIndex:2] setBadgeValue:[NSString stringWithFormat:#"%d",[count intValue]]];
}
Its doesn't change the UI at all. I would like to know how to update UI in AppDelegate actually? Anyone has an idea :)?
Here's the question:
Can one View Controller add another View Controller as an Observer to the defaultCenter before the second view has been loaded?
I have a model class that creates a NSURLSession, grabs some data, builds an array, and sends notifications that it's done (along with a pointer to the array).
My app loads with a Map View that instantiates the model, calls the method to create the array, listens for the notification, and drops pins using the array.
I have a Table View tab that I want to load using the array built by the map.
Can my Map View add my Table View Controller as an observer before the Table View is loaded?
Something like:
[[NSNotificationCenter defaultCenter] addObserver: TableViewController ...
Thanks for any insight. I'm figuring this out as I go.
-----------------EDIT--------------------
viewDidLoad from MapViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
_mapView.delegate = self;
_model = [[WikiModel alloc] init];
_lastArticleUpdateLocation = [[CLLocation alloc] initWithLatitude:0 longitude:0];
_lastUpdateUserLocation = [[CLLocation alloc] initWithLatitude:0 longitude:0];
// Listen for WikiModel to release updates.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadData:)
name:#"Array Complete"
object:_model];
//table view listener attempt ...
UITableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"tableViewController"];
[[NSNotificationCenter defaultCenter] addObserver:tvc
selector: #selector(updateDataSource:)
name:#"Array Complete"
object:nil];
[self.navigationController pushViewController:tvc animated:YES];
}
From the TableViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
// Listen for WikiModel to release updates.
/*
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateDataSource:)
name:#"Array Complete"
object:nil];*/
}
-(void)updateDataSource:(NSNotification *)notification
{
_wikiEntries = [[notification userInfo] objectForKey:#"wikiEntryArray"];
[self.tableView reloadData];
NSLog(#"************received***********");
}
This is possible as long as you pass the pointer to your view controller as the observer. Here's an example:
//Go to the detail view
VC2ViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"VC2ViewController"]; //ID specified in the storyboard
[[NSNotificationCenter defaultCenter] addObserver:dvc selector:#selector(notificationReceived:) name:#"MyNotification" object:nil];
[self.navigationController pushViewController:dvc animated:YES];
Then, you can post your notification as usual:
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:nil];
I just tested the above code and it worked fine for me, the following function was called in my detail view controller:
-(void)notificationReceived:(NSNotification *)notification {
NSLog(#"RECEIVED");
}
I have Tabbed Application with 5 tabs.
App starts on tab with index 0
When my app recive push notification, i want to push new view controller in tab with index 1.
My code:
AppDelegate
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)pushData {
UITabBarController *tabb = (UITabBarController *)self.window.rootViewController;
tabb.selectedIndex = 1;
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushImage" object:#"this is my item id from pushData"];
}
ProfileViewController (tab index 1)
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushImage:) name:#"pushImage" object:nil];
}
-(void) pushImage: (NSNotification*) notification {
NSString* text = notification.object;
NSLog(#"My id from pushData: %#", text);
}
My problem is that the ProfileViewController can not response to the notification, because the initialisation not already done, when the AppDelegate fire the notification.
If a manually open the tab 1 and switch back to tab 0 again, an then post the notification, it perfectly respons to it. So i need to post notification after the tab 1 is loaded, how can i hand this?
My solution of pushing new VC from AppDelegate in TabBarApplication
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)pushData {
// ......
if([[pushData objectForKey:#"type"] integerValue] == 0){
// ....
}
else if([[pushData objectForKey:#"type"] integerValue] == 2){
[self handleLikePush:pushData applicationState:application.applicationState];
}
}
-(void)handleLikePush:(NSDictionary *)pushData applicationState:(UIApplicationState) applicationState{
//..
DetailImageViewController *detailImage = [[DetailImageViewController alloc] initWithImageId:imageId];
[self pushViewControllerToCurrentTab:detailImage];
}
}
- (void)pushViewControllerToCurrentTab:(UIViewController *)vc{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UINavigationController *selectedTabNC = (UINavigationController *)tabBarController.selectedViewController;
if (selectedTabNC != nil) {
[selectedTabNC pushViewController:vc animated:YES];
}
else{
NSLog(#"NavigationController not found");
}
}
You can use
addObserver:instanceOfOtherClass
instead of addObserver:self
In appDelegate add these lines :
ProfileViewController *pvController=[ProfileViewController new];
[[NSNotificationCenter defaultCenter] addObserver:pvController selector:#selector(pushImage:) name:#"pushImage" object:nil];
to this method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)pushData {
UITabBarController *tabb = (UITabBarController *)self.window.rootViewController;
tabb.selectedIndex = 1;
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushImage" object:#"this is my item id from pushData"];
//**** add here
ProfileViewController *pvController=[ProfileViewController new];
//[[NSNotificationCenter defaultCenter] addObserver:pvController selector:#selector(pushImage:) name:#"pushImage" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushIamge" object:pvController];// userInfo:[NSDictionary dictionaryWithObject:#"1,2,3,4,5" forKey:#"categories_ids"]];
}
Have you tried adding the addObserver: method to your view controller's init method?