How to handle notification in UIViewcontroller from app delegate? - ios

I am getting notification appdelegate didReceiveRemoteNotification but i want to use this payload data in view controller how to do that?

There are a number of ways to achieve this, and the question is a little vague. Assuming that you have a view controller in your application this is active when your notification arrives, perhaps the simplest way would be to use an NSNotification to broadcast the payload from the app delegate to your interested view controller.
In your view controller:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedRemoteNotification:)
name:#"RemoteNotification"
object:nil];
And implement the method -receviedRemoteNotfication.
Then, in your app delegate's remote notification method:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"RemoteNotification"
object:payload];

You have to place your UITabBarController in a UINavigationController in your AppDelegate. Once you do this, then you declare the rootViewController of your application's main window a UINavigationController. Declare this in your header file of your AppDelegate:
#property (nonatomic, strong) UINavigationController * mainWindowRootViewController;
Then do this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[_window makeKeyAndVisible];
_mainWindowRootViewController = [UINavigationController new];
[self.window setRootViewController:_mainWindowRootViewController];
///code code code
[_mainWindowRootViewController setViewControllers:#[splashScreen, tabBarController] animated:TRUE];
...//code code code
return YES;
}
Now that you have your mainWindowRootViewController holding your splashScreen as the it's rootViewController and your tabBarController as the second viewcontroller on the stack, you can do this:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
UIViewController * commentsViewController = [UIViewController new];
UINavigationController * tempNAV = [[UINavigationController alloc] initWithRootViewController:commentsViewController];
[_mainWindowRootViewController presentViewController:tempNAV animated:TRUE completion:nil];
}
When you present the comments view controller, it will be presented over the entire stack of controllers including the UITabBarController and the splashScreen (if you have a splash screen). Also, to all the people who may say, "you can't present a UINavigationController with a UINavigationController", yes you can, try it for yourselves, it's amazing!
This assumes you have the comments view controller declared in the AppDelegate, if you have declared this "localNotif" somewhere else, then you can do this same presentation OVER the entire STACK of view controllers over the entire app window by using the following modifications:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
UIViewController * commentsViewController = [UIViewController new];
UINavigationController * tempNAV = [[UINavigationController alloc] initWithRootViewController:commentsViewController];
[[(YOURAppDelegate *)[UIApplication sharedApplication].delegate mainWindowRootViewController] presentViewController:tempNAV animated:TRUE completion:nil];
}

Related

iOS MMDrawerController objective-c login view controller

I am begin to study iOS and I try to do left navigation with MMDrawerController
my AppDelegate didFinishLaunchingWithOptions code is:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *leftView = [mainStoryboard instantiateViewControllerWithIdentifier:#"LeftViewController"];
UINavigationController *leftNav = [[UINavigationController alloc]initWithRootViewController:leftView];
UIViewController *centerView = [mainStoryboard instantiateViewControllerWithIdentifier:#"CenterViewController"];
UINavigationController *centerNav = [[UINavigationController alloc]initWithRootViewController:centerView ];
self.drawerController = [[MMDrawerController alloc] initWithCenterViewController:centerNav leftDrawerViewController:leftNav];
self.drawerController.openDrawerGestureModeMask = MMOpenDrawerGestureModePanningCenterView;
self.drawerController.closeDrawerGestureModeMask = MMCloseDrawerGestureModePanningCenterView;
self.window.rootViewController = self.drawerController;
[self.window makeKeyAndVisible];
// Override point for customization after application launch.
return YES;
}
So it's work fine, but I have LoginViewController on my app, and if user has no saved token on NSUserDefaults, I must show LogionViewController.
Of course side menu must be hidden on LoginViewController.
I Tried to switch to LoginViewController inside my CenterViewController:
- (void)viewDidLoad {
[super viewDidLoad];
LoginViewController * vc = [[LoginViewController alloc] init];
AppDelegate *app = [[UIApplication sharedApplication] delegate];
[app.drawerController setCenterViewController:vc withCloseAnimation:YES completion:nil];
}
But I have black screen only.
What I do wrong?
Thanks
What you're doing is a bit weird because you are setting the new centerViewController (of type LoginViewController) within the current one (of type CenterViewController), and once that is done the latter one will be deallocated because there are no more references to it. This might somehow be causing the black screen.
One solution would be to have the LoginViewController outside the MMDrawerController, and always present it at the beginning. If there is no token, then quickly (without animation) present the MMDrawerController and the LoginViewController won't even be seen. This way also allows you to easily dismiss back to the login screen if the user logs out.
Another option is to just present your LoginViewController from the CenterViewController modally (or however you like really) using presentViewController:animated:completion:, and then just dismiss it when they log in.

How do I access a view controller from AppDelegate.m during a background refresh

I am trying to implement background refresh in my app. I have a method refreshMessages that is inside one of my UIViewControllers (I am using a UINavigationController). I need to access this controller from AppDelegate.m.
Usually I would do something like this:
UINavigationController *navigationController = [self.window.rootViewController navigationController];
to get the navigation controller and I can then access them from there. But surely this won't work now. The app is in the BACKGROUND and no window is showing. Any thoughts on how to get around this? Thanks!
Here is my background refresh:
-(void)application:(UIApplication *)application
performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"Doing the background refresh");
UINavigationController *navigationController = [self.window.rootViewController navigationController];
NSLog(#"Number of controllers is %d", [[navigationController viewControllers] count]);
//There are zero controllers?!!! Must be because no window is showing
completionHandler(UIBackgroundFetchResultNewData);
}
Yes, you are right. The window will be nil since it will no longer be in the view hierarchy.
A cheeky solution would be to hold the reference of the view controller in the AppDelegate by creating a property in it. You can assign this when the application goes to the background by subscribing to the relevant notification in the view controller.
Edit: Code added
In your AppDelegate.h
#property (nonatomic, weak) YourViewController *yourViewController;
In YourViewController.m, somewhere in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
appWillResignActive's implementation
-(void)appWillResignActive:(id)sender {
YourAppDelegate *delegate = [UIApplication sharedApplication].delegate;
delegate.yourViewController = self;
}
In your completion handler
[self.yourViewController refreshMessages]
Also, make sure you remove the observer once the view controller is deallocated.

NavigationController presenting ViewController twice

I installed third party library using pods, which has it's own navigationController. I my existing project I am setting the rootViewController in the app delegate. I am pushViewController to the library ViewController (which is in it's own navigation stack). When I exit and then push to the library for a second time the ViewAlready seems to be there before transitioning the same view over the top.
In my appDelegate...
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
appbarViewController = [[AppBarViewController alloc] init];
[self loadNormalFlow];
[self.window makeKeyAndVisible];
}
- (void)loadNormalFlow
{
self.navigation = [[UINavigationController alloc]initWithRootViewController:appbarViewController];
self.window.rootViewController = self.navigation;
[self.navigation setNavigationBarHidden:YES];
}
-(void)displayLibraryView
{
ACSViewController *acs = [[ACSViewController alloc] init];
[self.navigation pushViewController:acs animated:nil];
}
Within library ViewController class to return back to original rootViewController i am using
[[UIApplication sharedApplication].delegate performSelector:#selector(loadNormalFlow)];
I seems like it is not properly dismissing the library ViewController, or it does a push twice? Any idea?

Pushing iOS UIViewController from NSObject class

I have the following code within my AppDelegate. It is used during checks for In App Purchase expiry, and if a subscription is expiring, will present a popup for the user to choose to renew, and if they do, it will push the view controller for the In App Purchases onto the stack.
I would like to shift the code out of AppDelegate, and into its own NSObject class (just for tidiness). However, how do I call push the View Controller from another class?
self.window.rootViewController doesn't exist on the NSObject class, so of course won't function.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UICollectionViewController *ivc = (UICollectionViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"IAPViewController"];
[navigationController pushViewController:ivc animated:YES];
In your NSObject class, when you want to push a vc, post a notification via NSNotificationCenter:
[[NSNotificationCenter defaultCenter] postNotificationWithName:#"PushMyViewControllerNote" object:nil];
And in AppDelegate.m register observer:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handlePushVCNotification:)
name:#"PushMyViewControllerNote"
object:nil];
//...
return YES;
}
//...
- (void)handlePushVCNotification:(NSNotification *)note
{
// First you must find currently visible view controller
// for how to do it, find it yourself :)
// but you can check https://gist.github.com/snikch/3661188
UIViewController *visibleVC = [self findVisibleVC];
UINavigationController *nc = visibleVC.navigationController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UICollectionViewController *ivc = (UICollectionViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"IAPViewController"];
[nc pushViewController:ivc animated:YES];
}
What you should do is create a separate class that inherits from NSObject. Call it something like AppPurchase. Then, import your AppPurchase class into your app delegate. As for pushing the view controller, that code should be separate from your AppPurchase class.
The AppPurchase class is part of your Model, and should not be responsible for pushing view controllers around. If data changes in your AppPurchase instance, then the controller can take some action and alter your View.
You should look into learning more about MVC or Model-View-Controller.

How to swap the window.rootViewController without using an UINavigationController?

In the AppDelegate I set an UIViewController, let's call it VC, as the rootViewControlloer for my app:
-(BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
{
self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
UIViewController *VC = [UIViewController alloc] init];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
return YES;
}
Once VC is on the screen, it asks the user a couple of questions to better configure the app before the real use.
As soon as I know what the user wants I need to swap VC with an UITabBarController, let's call it TBC, with three UINavigationController anchored to it.
How can I push TBC from VC whithout putting VC inside an UINavigationController and then use it to push TBC?
I am already able to accomplish the swap using the UINavigationController.I want a direct transiction from VC to TBC, a swap of the self.window.rootViewController whitout the need to use the extra UINavigationController.
Instead of navigating through the view controllers just create a method in app delegate which would change the root controller such as
-(void)showTBC
{
self.TBC=[[UITabbarcontroller alloc]init];
[self.window setRootViewController:self.TBC];
[self.window makeKeyAndVisible];
}
and den in your VC right after the user selects the answer make an instance of app delegate
in VC such as
AppDelegate *ap=(AppDelegate *)[[UIApplication sharedApplication]delegate];
and call
[ap showTBC];
…it worked for me..give it a try...

Resources