user2924482
user2924482

Reputation: 9120

iOS Objective-C: How to identify the view controller is presenting thru UINavigationController?

I have multiple viewControllers on my implementation for example:

ViewControllerA
ViewControllerB
ViewControllerC
ViewControllerD

But the deeplinks I need to load them in ViewControllerC but I don't know if that viewcontroller is been load it (initialized) yet or if is present.

I have tried this from appDeelegate:

ViewControllerC *rootViewController = [[ViewControllerC alloc] init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

But it seems like is creating a new instance of the viewController.

My question to you guys, how can I grab the instance ViewControllerC load it in the app or how can I detect if ViewControllerC is not load it yet?

I'll really appreciate your help or work around.

Upvotes: 0

Views: 2142

Answers (2)

danh
danh

Reputation: 62676

As you pointed out, allocating a view controller in order to determine if it is presented makes no sense. Will your app always have a navigation controller at its root? If so, you can get it this way...

// in the app delegate
AppDelegate *appDelegate = self;

// or, if not in the app delegate
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

// either way
UINavigationController *navController = (UINavigationController *)[[appDelegate window] rootViewController];

Notice the potentially reckless cast of the root vc as a UINavigationController. That's reckless only if some other sort of VC can sometimes be at the root. If that's the situation in your app, then you need to test...

UIViewController *vc = [[appDelegate window] rootViewController];
if ([vc isKindOfClass:[UINavigationController self]]) {
    UINavigationController *navController = (UINavigationController *)vc;
    // carry on from here
} else {
    // decide what your "deep link" function does when the wrong root vc is present.  maybe start over?
}

Finally, and I think the problem you're getting at, how do we determine if a ViewControllerC is present, and how do we present it if not? The first part is easy because navigation controllers have a viewControllers property. That's an array representing the "stack", where the first item is the root and the last item is on top. So...

NSInteger index = NSNotFound;
for (UIViewController *vc in navController.viewControllers) {
    if ([vc isKindOfClass:[UIViewController self]]) {
        index = [navController.viewControllers indexOfObject:vc];
    }
}
if (index != NSNotFound) {
    // it's on the stack
}

Here's the way to ask if it's at the top of the stack...

[navController.viewControllers.lastObject isKindOfClass:[ViewControllerC self]]

What to do if its not on the stack is up to you. One idea is to just push one. Do that the way you do it in your app already. What if it is on the stack, but not on top? If you wanted animation to get there, you'd pop to it (animating the last pop). Since this is a deep link, you probably don't care about the animation. Just truncate the nav controllers view controller list...

if (index != NSNotFound) {
    // it's on the stack
    navController.viewControllers = [navController.viewControllers subarrayWithRange:NSMakeRange(0, index+1)];
}

Upvotes: 1

Sore
Sore

Reputation: 186

For check if root view controller is a ViewControllerC

Swift:

if type(of: UIApplication.shared.keyWindow?.rootViewController) == ViewControllerC.self{
    debugPrint("RootViewController is a ViewControllerC")
}

Objective-C:

if ([[[[UIApplication sharedApplication] keyWindow] rootViewController] class] == [ViewControllerC class]){
        NSLog(@"RootViewController is a ViewControllerC");
    }

For check if ViewControllerC is presented on root view controller

Swift:

if let rootViewController = UIApplication.shared.keyWindow?.rootViewController{
    if type(of: rootViewController.presentedViewController) == ViewControllerC.self{
        debugPrint("ViewControllerC is presented on rootViewController")
    }
}

Objective-C:

UIViewController *viewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    if (viewController != nil){
        if ([viewController.presentedViewController class] == [ViewControllerC class]){
            NSLog(@"ViewControllerC is presented on rootViewController");
        }
    }

Set root view controller as ViewControllerC

Swift:

if UIApplication.shared.keyWindow != nil{
    let viewController:ViewControllerC = ViewControllerC()
    //You can get above instance from Storyboard if you wanna
    UIApplication.shared.keyWindow!.rootViewController = viewController
}

Objective-C:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if (window != nil){
    ViewControllerC *viewController = [[ViewControllerC alloc] init];
    //You can get above instance from Storyboard if you wanna
    window.rootViewController = viewController;
}

For push view controller on navigation controller from root if exists

Swift:

    if UIApplication.shared.keyWindow != nil{
        if let navigationController = UIApplication.shared.keyWindow!.rootViewController as? UINavigationController{
        let viewController:ViewControllerC = ViewControllerC()
        //You can get above instance from Storyboard if you wanna
        navigationController.pushViewController(viewController, animated: true)
        }
    }

Objective-C:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    if (window != nil){
        UINavigationController *navigationController = (UINavigationController*)window.rootViewController;
        if (navigationController != nil){
            ViewControllerC *viewController = [[ViewControllerC alloc] init];
            [navigationController pushViewController:viewController animated:true];
        }
    }

Now you can do a lot of stuff, for example get the instance of ViewControllerC from navigation controller if exists

Objective-C:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    if (window != nil){
        UINavigationController *navigationController = (UINavigationController*)window.rootViewController;
        if (navigationController != nil){
            UIViewController *viewController = [navigationController topViewController];
            if ([viewController class] == [ViewControllerC class]){
                NSLog(@"Do what you want with viewControllerC instance");
            }
        }
    }

Upvotes: 0

Related Questions