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 :)?
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 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 )
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 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];
I am currently developing an app that will need to return to another view after running in the background for more than five minutes. In order to do this, I will have to have a timer running in the background after the the Home button has been pressed or in case of an interruptions such as an SMS or a telephone call, then, after five minutes the app will need to go to another view. I know that the applicationDidBecomeActive method will have to be used, but how? I also know that a view can be refreshed in applicationDidBecomeActive but how is that done? ( I am not using storyboards.)
Actually, you should do this with the applicationDidEnterBackground applicationWillEnterForeground delegate methods of UIAppDelegate or by registering to the appropriate system notifications (didBecomeActive is called on other occasions too, such as when a UIAlertView is dismissed from screen).
This should be something in the lines of (may include syntax problems, I'm textbox-coding here):
In the viewDidLoad method of your view controller, register to the notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
Implement the willEnterForeground: and didEnterBackground: methods. In willEnterForeground: sample the current time using CACurrentMediaTime() or [NSDate date]. In didEnterBackground: sample the time again and calculate the time difference. Since this method is implemented inside the view controller, you can manipulate the subviews of your self.view as you wish.
Do not forget to remove the observers on your dealloc method (viewDidUnload is deprecated since iOS 6.0, so beware):
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil]
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil]
Here's how you can do it. I just made a test app and I confirm that it works beautifully. Code:
#import "AppDelegate.h"
#import "ViewController.h"
#import "theView.h"
NSTimer *theTimer;
UIViewController *theViewController;
BOOL theTimerFired = NO;
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Set a 5 minute timer (300 seconds)
theTimer = [NSTimer scheduledTimerWithTimeInterval:300.0 target:self selector:#selector(presentVC) userInfo:nil repeats:NO];
}
- (void)presentVC
{
// Set a boolean to indicate the timer did fire
theTimerFired = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Check to see if the timer did fire using the previous boolean we created
if (theTimerFired == YES)
{
theViewController = [[UIViewController alloc]initWithNibName:#"theView" bundle:nil];
[self.viewController presentViewController:theViewController animated:YES completion:NULL];
[theTimer invalidate];
}
}
#end