We have in-build methods to present and navigate a new controller from currently visible controller.
We can use "presentViewController: animated: completion:" method to present a new controller and "pushViewController: animated:" method to push a new controller in navigation controller stack.
But for presenting and navigating a new controller we must know current visible controller, our presenting and navigation code must be inside the current visible controller file. Suppose our project require to display a controller on notification call, when user receive a notification a controller will present. In this scenario we don't know when the app will receive notification, and at the time of receiving notification, which controller is on top. So what is the best solution of this problem? first option is write code inside all classes and call this method on the basis of local notification, when a controller appear its add a observer for present a controller and when its disappear remove that observer. But, is this good option/solution? No, its not a solution of problem. If we accept this approach, than we need to add extra work to controller local notification for present and push controller. Instead of accepting first approach we will find the current visible controller and present new controller from any where of the application and no need to write same code again and again in side all classes.
In this blog post i am going to find current visible controller and present a new controller.
Lets start,
Go to your project and add new category for UIWindow.
Inside .h file add following methods
- (UIViewController *)visibleViewController;
+ (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc;
Now switch to .m file and define methods
- (UIViewController *)visibleViewController {
UIViewController *rootViewController = self.rootViewController;
return [UIWindow getVisibleViewControllerFrom:rootViewController];
}
+ (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc {
if ([vc isKindOfClass:[UINavigationController class]]) {
return [UIWindow getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
return [UIWindow getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]];
} else {
if (vc.presentedViewController) {
return [UIWindow getVisibleViewControllerFrom:vc.presentedViewController];
} else {
return vc;
}
}
}
//--------
In the first method, we are not doing any thing, just we are calling the second method with root controller of window.
In the second method, we are checking the kind of controller(is a kind of UINavigationController, UITabBarController, presentedViewContrller) and returning top of the controller.
Go to ViewController.m file and import UIWindow category class
and add below method
-(void) displayFullScreenMessage{
//create a instance of controller
MessageViewController *controller = [[MessageViewController alloc] initWithNibName:@"MessageViewController" bundle:nil];
//get main window
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
//get current visible controller
UIViewController *visiblecontroller = [mainWindow visibleViewController];
//present a controller
[visiblecontroller presentViewController:controller animated:YES completion:nil];
}
Now we have enough code for display a controller on the top of the controller.
Call the above method and display controller.
We can use "presentViewController: animated: completion:" method to present a new controller and "pushViewController: animated:" method to push a new controller in navigation controller stack.
But for presenting and navigating a new controller we must know current visible controller, our presenting and navigation code must be inside the current visible controller file. Suppose our project require to display a controller on notification call, when user receive a notification a controller will present. In this scenario we don't know when the app will receive notification, and at the time of receiving notification, which controller is on top. So what is the best solution of this problem? first option is write code inside all classes and call this method on the basis of local notification, when a controller appear its add a observer for present a controller and when its disappear remove that observer. But, is this good option/solution? No, its not a solution of problem. If we accept this approach, than we need to add extra work to controller local notification for present and push controller. Instead of accepting first approach we will find the current visible controller and present new controller from any where of the application and no need to write same code again and again in side all classes.
In this blog post i am going to find current visible controller and present a new controller.
Lets start,
Go to your project and add new category for UIWindow.
Inside .h file add following methods
- (UIViewController *)visibleViewController;
+ (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc;
Now switch to .m file and define methods
- (UIViewController *)visibleViewController {
UIViewController *rootViewController = self.rootViewController;
return [UIWindow getVisibleViewControllerFrom:rootViewController];
}
+ (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc {
if ([vc isKindOfClass:[UINavigationController class]]) {
return [UIWindow getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
return [UIWindow getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]];
} else {
if (vc.presentedViewController) {
return [UIWindow getVisibleViewControllerFrom:vc.presentedViewController];
} else {
return vc;
}
}
}
//--------
In the first method, we are not doing any thing, just we are calling the second method with root controller of window.
In the second method, we are checking the kind of controller(is a kind of UINavigationController, UITabBarController, presentedViewContrller) and returning top of the controller.
Go to ViewController.m file and import UIWindow category class
and add below method
-(void) displayFullScreenMessage{
//create a instance of controller
MessageViewController *controller = [[MessageViewController alloc] initWithNibName:@"MessageViewController" bundle:nil];
//get main window
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
//get current visible controller
UIViewController *visiblecontroller = [mainWindow visibleViewController];
//present a controller
[visiblecontroller presentViewController:controller animated:YES completion:nil];
}
Now we have enough code for display a controller on the top of the controller.
Call the above method and display controller.