I'm trying to implement circular dependency between my AppDelegate and my ViewController to call methods from my AppDelegate to my ViewController but it's not working.
See my code as follow:
AppDelegate.h:
#class ViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong,nonatomic) ViewController *mainView;
#end;
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
[self.mainView doSomething];
return YES;
}
ViewController.h:
#import <UIKit/UIKit.h>
#class AppDelegate;
#interface ViewController : UIViewController
#property (strong,nonatomic) AppDelegate *delegate;
-(void)doSomething;
#end;
ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
}
- (void)doSomething
{
NSLog(#"doing something");
}
I don't have any errors or warnings but the method doSomething has never been call. Any of you knows why or what I'm doing wrong?
I'll really appreciate your help.
This has nothing to do with circular dependencies.
As you've been told, the method doSomething is never called because you are saying
[self.mainView doSomething];
...at a time when self.mainView has never been given a value. Merely declaring a property
#property (strong,nonatomic) ViewController *mainView;
...does not point the variable mainView at your actual ViewController instance; it is nil, and a message to nil generates no error and causes nothing at all to happen.
You could fix this by having the ViewController set a reference to itself by adding one line to your code:
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
self.delegate.mainView = self; // <--
}
But don't! The simple truth is that your entire approach here is wrong. There should be no need whatever to keep a reference to your ViewController inside your app delegate. Your app has, at every moment, a view controller hierarchy. The app delegate should know where the ViewController is within that hierarchy.
Here we are in your app delegate when a link message comes in:
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
At that moment, it is the app delegate's job to know where the ViewController is in the view controller hierarchy, and even to arrange the view controller hierarchy so that the ViewController's scene is showing if it wasn't already, in response to the link message.
How you do that depends on the structure of your view controller hierarchy. You start at the top of the hierarchy, which, for the app delegate, is [[self window] rootViewController], and work your way down to the existing view controller you want to talk to.
You have not told us your view controller hierarchy structure, so it's impossible to help in detail. But let's say, for example, that your app revolves around a navigation controller interface. Then, for the app delegate, [[self window] rootViewController] is the navigation controller, and so you can cast to that class: (UINavigationController*)[[self window] rootViewController]. Then, if the ViewController is the navigation controller's root view controller, you take its viewControllers[0] to reach it, and again you cast as needed:
UINavigationController* nav = (UINavigationController*)[[self window] rootViewController];
ViewController* vc = (ViewController*)nav.viewControllers[0];
Now you can send the doSomething message to vc. But that's just an illustration; the precise details will depend on where the ViewController really is, within the view controller hierarchy. And of course you might also want to pop view controllers so that the ViewController's scene is actually showing, since you likely cannot guarantee that it is showing at the time the link message comes in.
Another completely different way of handling this situation is to use the NSNotificationCenter to post a notification for which the ViewController instance has registered. That is often a solution when you do not know exactly where in the view controller hierarchy your view controller is. But in this situation, you should know that.
Try the below code :
AppDelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[ViewController sharedInstance] doSomething];
return YES;
}
ViewController.h
+ (ViewController *)sharedInstance;
- (void)doSomething;
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
+ (ViewController *)sharedInstance {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
return [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
}
- (void)doSomething {
NSLog(#"ViewController is doing something");
}
Output :
ViewController is doing something
I don't have any errors or warnings but the method doSomething has never been call. Any of you knows why or what I'm doing wrong?
It happens because you haven't initialised an instance of ViewController. So, you have a nil at mainView. When you try to send a message "doSomething" to mainView you send message to nil. At Objective-C when you send a message to nil nothing is happens.
You should initialise an instance before you try to invoke the method. For example, at didFinishLaunchingWithOptions with such code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.mainView = [ViewController new];
return YES;
}
It will works if you create views programatically. If you use a storyboards or xib you should use another methods.
Now you should see "doing something" at console when openURL is invoked.
BTW, you have a retain cycle between app delegate and view controller. So, your mainView will never release even if you make it explicitly nil. To avoid a retain cycle you should use attribute weak at ViewController.h:
#property (nonatomic, weak) AppDelegate *delegate;
You can do that by the below code but excuse me for doing it with Swift:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var mainVC: ViewController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
mainVC = ViewController()
mainVC?.doSomething()
setupMainViewController()
return true
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
mainVC?.doSomething()
return true
}
func setupMainViewController(){
guard window != nil else{
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = mainVC
window?.makeKeyAndVisible()
return
}
window?.rootViewController = mainVC
}
and the MainViewController will be:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
doSomething()
}
func doSomething(){
print("do something with \(self)")
}
I appreciate all the other answers, I come here with a different approach. Generally, I used in my projects.
NSNotificationCenter defaultCenter Please check the code below.
Viewcontroller.m
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//self.delegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
// HERE REGISTER NOTIFICATION WHEN SCREEN IS APPEAR
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doSomething:)
name:#"TestNotification"
object:nil];
}
// HERE ADDS NOTIFICAIOTN AS PARAMETERS
- (void)doSomething :(NSNotification *) notification
{
NSLog(#"doing something");
// IF YOU PASSED VALUE WITH THE NOTIFICAIONT THEN IT WILL SHOW HERE
NSDictionary *userInfo = notification.userInfo;
id myObject = [userInfo objectForKey:#"someKey"];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// HERE REMOVE NOTIFICATION OBSERVER
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
AppDelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
//WITHOUT SENDING ANY DATA
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];
// IF YOU WANT TO SEND ANY INFROMATION THEN PLEASE USE THIS METHODS
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:myObject forKey:#"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName:
#"TestNotification" object:nil userInfo:userInfo];
return YES;
}
Here you do not need to check the visible view controller and no allocation required. if your screen is in the top then your methods are called otherwise not.
Good luck! :-)
Related
I want to display a specific UIViewController when a push notification is received and the user tap on that notification. I made some research and tried a few things without success.
I tried the following code, it works on UIAlertController but it didn't display the specific UIViewController I wanted. Please help me out. I am using Xcode 6.3.
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if(apsInfo) {
UIStoryboard *myStoryBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
notificationViewController *nvc = [myStoryBoard instantiateViewControllerWithIdentifier:#"notificationViewController"];
[self.window.rootViewController presentViewController:nvc animated:YES completion:nil];
}
return YES;
}
Thanks in advance
You could create a 'Router' object that handle the notification payload, and pass that object from ViewController to ViewController, building the navigation stack step by step.
Here is a link to a sample project I made to illustrate that concept. For the sake of the demo, the 'Router' is built following a call to buildNavigationStack in application:application handleOpenURL:, but you could easily change that to use the userInfo dictionary received in application:didReceiveRemoteNotification:fetchCompletionHandler:.
For this need, I create a UIViewController variable called currentViewController in my AppDelegate class or my Singleton class if it exists in the project.
For every VC created, I add the following line inside the viewWillAppear and viewDidAppear:
[(myAppDelegate *)[[UIApplication sharedApplication] delegate] setCurrentViewController:self];
This way the VC being shown on the screen is always kept in an ivar.
So in - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo or where ever you are presenting the alertViewController you can present or push your new VC easily.
[self.currentViewController presentViewController:vc animated:YES completion:nil];
Full Detail Solution:
In this approach the critical and tricky part is setting the currentViewController in a singleton class. Rest will be very straight forward.
Create Singleton Class:
//CapsHelper.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface CAPSHelper : NSObject
{
}
#property (nonatomic, strong) UIViewController * currentViewController;
+ (instancetype)sharedHelpers;
//CapsHelper.m
#import "CAPSHelper.h"
#interface CAPSHelper ()
#end
#implementation CAPSHelper
#synthesize currentViewController;
#pragma mark Singleton Methods
+ (instancetype) sharedHelpers
{
static CAPSHelper *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
Lets say you have around 10 viewcontrollers in your app called VC1, VC2, .., VC10 etc. In each VC's viewWillAppear:animated:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[CAPSHelper sharedHelpers] setCurrentViewController:self]
}
Or if this seems like lots of repetition, you can create a new class and override viewWillAppear:animated: and you wont have trouble trying to remember adding above to new VC's you will create in the future.
At this moment we are all set, every time a VC is being presented to the screen, we are holding it in a variable called currentViewController, and it is accessible from everywhere by importing #import "CAPSHelper.h"
//AppDelegate.m
#import "AppDelegate.h"
#import "CAPSHelper.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSDictionary *userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if(apsInfo)
{
if([[CAPSHelper sharedHelpers] currentViewController])
{
//UIViewController * pushNotificationViewController = [[UIViewController alloc] ..... This is your specific VC which you want to present when a PN is recieved..
[[[CAPSHelper sharedHelpers] currentViewController] presentViewController:pushNotificationViewController animated:YES completion:nil];
}
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if(apsInfo)
{
if([[CAPSHelper sharedHelpers] currentViewController])
{
//UIViewController * pushNotificationViewController = [[UIViewController alloc] ..... This is your specific VC which you want to present when a PN is recieved..
[[[CAPSHelper sharedHelpers] currentViewController] presentViewController:pushNotificationViewController animated:YES completion:nil];
}
}
}
I want to access to an IBOutlet of my first Viewcontroller by AppDelegate class. My project is based with a storyboard and there isn't the reference with the first Viewcontroller.
What's the to do it?
I know that I should set this IBOutlet as a property in first Viewcontroller, but in AppDelegate? How I can access to it?
Thanks
You can access your rootViewController from your app's delegate with :
self.window.rootViewController
Example :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MyVCClass *firstVC = (MyVCClass*)self.window.rootViewController;
[firstVC someMethod];
}
Careful, your ViewController may not have been yet loaded / initiated.
Because you don't set the rootViewController for your app's UIWindow, then doing
[[UIApplication sharedApplication].keyWindow rootViewController] will give you nil.
If you use storyboards for your navigation then simply you can do this to get the rootViewController
UIViewController *vc = [self.navigationController.viewControllers objectAtIndex:0];
First import your ViewController in AppDelegate.m like this :
#import "YourViewController"
Then in AppDelegate.m place the below code
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
YourViewController * view = [[YourViewController alloc]init];
self.window.rootViewController = view;
}
Does anyone know of a way to have a UITabBarButton that, rather than segueing to another view controller, will perform another function, e.g. call a method?
My iPad app utilises a tab bar but the client wants the right-most button to perform a check for updates on a server; however I can't seem to to figure out how to have a button that won't switch views when pressed. I tried deleting the segue but that removes the button as well.
-EDIT-
screenshot and code snippet added for clarity. The tab labelled Sync is the one I want not to open a viewController:
AppDelegate.h:
#interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UIViewController *viewController;
#end
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window makeKeyAndVisible];
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
tabBarController.delegate = (id)self;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidTimeout:) name:kApplicationDidTimeoutNotification object:nil];
return YES;
}
and:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
NSLog(#"vc = %#", viewController);
return YES;
}
Look at the UITabBarControllerDelegate method :
– tabBarController:shouldSelectViewController:
If selectViewController == your last tab bar, return NO and perform others actions
EDIT :
Look at the example I've made :
AppDelegate.h
#interface ISAppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
tabBarController.delegate = (id)self;
return YES;
}
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
// here check if "viewController" is your last tab controller, then return NO and perform some actions you need
if (viewController = self.lastTabController) {
// do some actions
return NO;
}
return YES;
}
SOLUTION
Make sure in the plist that the storyboard name is listed as the main storyboard file name.
I have a Storyboard with a UINavigationViewController that's connected to a NavigationViewController class and it's set as the UIWindow rootViewController. When the app runs (in the Simulator (5.1)) I get a blank black screen with the blue-ish navigation bar on the top.
The first problem is that in the storyboard, I set the navigation bar to black. I also set the status bar to translucent black. Neither styles are being honored when the app runs.
And the second problem is that the navigation controller's view is empty even though in the storyboard it has a relationship to a UITableViewController.
How can I fix both of these issues. I just started using Xcode again and had been using 4.0 before so the storyboards are throwing me off...
UPDATE
Here's the code as requested. Obviously I can't post the storyboard (can I?).
AppDelegate:
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigationController = [[NavigationViewController alloc] init];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#end
NavigationViewController:
#import "NavigationViewController.h"
#interface NavigationViewController ()
#end
#implementation NavigationViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The problem is that you are setting as the root controller a completely blank root controller, not the one from the story board. What you want to do is to delete that part of the code, and simply on the storyboard click the thing that says "is initial view controller"
When using storyboards you usually dont have to modify the appdelegate, because xcode sets which is the initial view that will appear and all of that based solely on how you set the storyboard. You can check this in the plist where it says which storyboard will be used as the main one.
If you want to load your navigation controller like that then you can do something like that you would have to get the viewcontroller from the storyboard itself and present it.
instantiateViewControllerWithIdentifier
but there is no need for that when using storyboards as it automatically loads whichever is set as the initial one (which can be seen as the viewcontroller with the arrow pointing at it)
Your app delegate method should look like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
I have an application with tab bar and 3 different View Controller. one of these imanage a UItableView that I designed through Interface Builder (storyboard) and I set the it's view controller class in the Inspector -> inspector identity -> and I set class field there, hence, I have no control when this view controller get instantiated, as it's done through storyboard when user click on tab bar. notice, i'm new to objective C and iOS programming.
the issue that I'm facing, i'm also using remote notification. hence, when I receive a remote notification message in "didReceiveRemoteNotification" in the AppDelgate class. I need to update UI interface (above ViewController), but the issue I don't have a reference (pointer) to this ViewController from my AppDelgate class ( or do I?). the problem this ViewController instantiated by storyboard nor programmatically, otherwise I could have kept a reference to it.
I did some reading and I understand I could do this communication via NSNotification, but I think this will be an overkill for a problem that maybe arise just because I'm new to this and I don't have full understanding of iOS development.
Thanks,
NSNotifications are easy to use and are probably the right solution.
In the app delegate that needs to send the message, just put:
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:someObjectYouWantToPassCouldBeAppDelegateOrRemoteNotificationObjectOrAnything];
In the view controller that is receiving the message, put:
-(void)viewDidLoad
{
[super viewDidLoad];
//you can add as many of these as you like to handle different notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"MyNotification" object:nil];
}
-(void)viewDidUnload
{
//make sure you remove every observer you've added here
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"MyNotification" object:nil];
[super viewDidUnload];
}
-(void)dealloc
{
//clean up in case viewDidUnload wasn't called (it sometimes isn't)
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
//use a different handler method for each notification
//the method name should match the selector in your observe call in viewDidLoad
-(void)handleNotification:(NSNotification *)notification
{
WhateverClassOfObjectYouWerePassing *object = notification.object;
//now you have a reference to the object that was passed from your app delegate
}
For different methods you want to call, just and a new notification name and a new handler method.
Your app Delegate will have a window property which points to the apps window.
Window Property has a -rootViewController property/method.
For your Tab Based Application it would return you the TabViewController.
Each TabViewController have a method -(NSArray *)viewControllers which returns the ViewControllers inside the Tab. These are arranged in the order.
To Access your applications AppDelegate use [[UIApplication sharedApplication]delegate]
Once you have these viewcontrollers you would know which all viewController these are since you have added it in the XIB files. and can perform your methods
1. Communicate two ViewControllers
If you want to communicate two ViewControllers, you should use #protocol as Apple recommended:
ViewController1.h
#interface ViewController1 : UIViewController<ViewController2Delegate, ViewController2DataSource>
#end
ViewController1.m
- (IBAction)goToViewController2:(id)sender{
if(viewController2 == nil) {
ViewController2 *viewController = [[ViewController2 alloc]
initWithNibName:#"View2" bundle:[NSBundle mainBundle]];
viewController2 = viewController;
}
//...
viewController2.delegate = self;
viewController2.dataSource = self;
[self.navigationController pushViewController:viewController2 animated:YES];
}
- (NSString)viewController:(ViewController2 *)controller itemForSomethingAtIndex:(NSInteger)index{
//Send to viewController2 what it needs
return [items objectAtIndex: index];
}
- (void)viewController:(ViewController2 *)controller didFinishEnteringItem:(NSString *)item{
//Handle the result from the viewController2
NSLog(#"result: %#", item);
}
ViewController2.h
#import <UIKit/UIKit.h>
// Define your delegate methods to return items to the delegate of this viewController
#protocol ViewController2Delegate <NSObject>
- (void)viewController:(ViewController2 *)controller didFinishEnteringItem:(NSString *)item;
#end
// Define your dataSource methods to send items from the dataSource to this viewController
#protocol ViewController2DataSource <NSObject>
- (NSString)viewController:(ViewController2 *)controller itemForSomethingAtIndex:(NSInteger)index;
#end
#interface ViewController2 : UIViewController
#property (nonatomic) id <ViewController2Delegate> delegate;
#property (nonatomic) id <ViewController2DataSource> dataSource;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize //...;
- (void)someMethod {
//Get someThing from controller1
NSString *item = [dataSource viewController: self itemForSomethingAtIndex:0];
//Return someThing to controller1
[delegate viewController: self didFinishEnteringItem: item];
}
2. Communicate backgroundTask with viewController
If you want to communicate a background task or handle a push notification, use #NickLockwood's answer. But this dont gonna work if the viewController its not loaded. In this case you should handle that in the AppDelegate:
//Get the appDelegate instance
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//And call your custom method to show what it needs
[appDelegate customMethod];
Your custom method should call controllers consecutevly like:
AppDelegate > RootController > ViewController1 > ViewController2 > myMethod
//do something if viewController2 is visible to the user or push it before do something.
//if you use navigation controller, then you need to ask for the position and className