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");
}
Related
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?
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 :)?
So I've got a UIActivityViewController that takes up half the screen when my app runs, what happens is when I click the half it doesn't take up then it'll disappear and my original blank ViewController appears.
Is it possible to permanently keep the UIActivityView up until the user clicks on one of the sharing options (such as Facebook, or Mail)? Otherwise I'll just work around it.
I load the ActivityView with:
-(void)viewDidAppear:(BOOL)animated{
UIActivityViewController *controller = [[UIActivityViewController alloc]initWithActivityItems:#[#""] applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
}
Yes, it is possible, you can try something like
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(showAViewController) name:#"showAViewController" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dissmissAViewController) name:#"dissmissAViewController" object:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self name:#"showAViewController" object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:#"dissmissAViewController" object:nil];
}
-(void)showAViewController{
self.view.userInteractionEnabled=NO;
}
-(void)dissmissAViewController{
self.view.userInteractionEnabled=YES;
}
When you are showing a view controller on top of another view controller just call
[[NSNotificationCenter defaultCenter] postNotificationName:#"showAViewController" object:nil];
After you dismiss it or remove it, just call:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"dissmissAViewController" object:nil];
I have tried many things, none of which are working. I have an SKScene, and when the game is over, I want it to go back to the original view controller. Thank you in advance.
I have tried this in my SKScene
homeScreenViewController *viewCont = [[homeScreenViewController alloc] init];
[viewCont viewDidLoad];
This in my other view controller
constructinoViewController *view = [[constructinoViewController alloc ] init];
[self presentViewController:view animated:YES completion:nil];
It mostly says The view is not in the view hierarchy.
You need a way to send the parent viewController a message.
In your viewController which presents the SKScene, add the following line in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(closeScene) name:#"closeScene" object:Nil];
Also, add this method
-(void)closeScene
{
//Remove the SKView, or present another viewController here.
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"closeScene" object:nil];
}
Then in your SKScene, at the point where your game ends,
[[NSNotificationCenter defaultCenter] postNotificationName:#"closeScene" object:nil];
You can do this by using delegates as well.
If you have presented the ViewController, then you need to dismiss it to return to previous ViewController.
You should use
[self dismissViewControllerAnimated:YES completion:NULL];