AppDelegate, rootViewController and presentViewController

前端 未结 6 2087
南方客
南方客 2020-11-27 15:38

I\'m doing the Facebook integration tutorial, I want to show my MainViewViewController if the user has a valid token for the current state otherwise I want to show LoginView

相关标签:
6条回答
  • 2020-11-27 16:12

    Sometimes presenting modal view controller from window.rootViewController may produce the same warning & have no effect. Example of such hierarchy of view controllers:

    1. [MYUITableViewController] (presented modally by MYUIViewController )
    2. [MYUIViewController] (rootViewController of UINavigationController below)
    3. [UINavigationController] (root)

    Now calling

    [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:[UIViewController new] animated:YES completion:nil];
    

    will cause this exact warning (tested both on iOS6 & 7 Sim)

    Solution: Instead of using rootViewController - use the top one presented by it:

        UIViewController *topRootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
        while (topRootViewController.presentedViewController) 
        {
            topRootViewController = topRootViewController.presentedViewController;
        }
    
        [topRootViewController presentViewController:yourController animated:YES completion:nil];
    
    • Sometimes keyWindow may have been replaced by window with nil rootViewController (showing UIAlertViews, UIActionSheets on iPhone, etc), in that case you should use UIView's window property.
    0 讨论(0)
  • 2020-11-27 16:13

    I had the same issue. Based on the answer to this question, I added [self.window makeKeyAndVisible] just before presentViewController:animated:completion:, and that fixed it for me.

    In your case, showLoginView becomes

    - (void)showLoginView
    {
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
        LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
        [self.window makeKeyAndVisible];
        [self.window.rootViewController presentViewController:loginViewController animated:YES completion:NULL];
    }
    
    0 讨论(0)
  • 2020-11-27 16:16

    You can launch a new viewController from root like this in Objective-C

    UIViewController *presenter = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
    
    [presenter presentViewController:yourViewController animated:YES completion:nil];
    

    Don't forget to add this:

    #import "AppDelegate.h"
    
    0 讨论(0)
  • 2020-11-27 16:28

    Stepan Generalov's answer was the right one for me in Swift 3!!!
    Of course with the new syntax etc. so I'll copy it in here:

    let sb = UIStoryboard(name: "Main", bundle: nil)
    let vc = sb.instantiateViewController(withIdentifier: "MainApp") as! ViewController
    
    var topRootViewController: UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!
    while((topRootViewController.presentedViewController) != nil){
        topRootViewController = topRootViewController.presentedViewController!
    }
    topRootViewController.present(vc, animated: true, completion: nil)
    

    "MainApp" is my main view controller's identifier in this case.

    I know there are other ways but if you need to have different URL schemes for opening different parts of your App, you must handle it in AppDelegate so this is perfect because in the

    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {}
    

    method, you can just check what url is as a String and then decide if you execute the above written code or maybe a similar one with a different identifier for an other view controller (withIdentifier)

    0 讨论(0)
  • 2020-11-27 16:31

    In Swift 3 :-

    let storyboard = UIStoryboard(name: "Login", bundle: nil)
    let viewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
    window?.makeKeyAndVisible()
    window?.rootViewController?.present(viewController, animated: true, completion: nil)
    
    0 讨论(0)
  • 2020-11-27 16:32

    In case, when you're not using a storyboard. First you need to create YourViewController. Go File -> New -> File... (or shortCut - command + N)

    After that, choose Cocoa Touch Class. Click Next, or Enter

    Than type name for your viewController and click Next

    #import "AppDelegate.h"
    #import "YourViewController.h"
    
    @interface AppDelegate ()
    
    @end
    
    @implementaion AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // Init window
    self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    [self.window makeKeyAndVisible];
    
    // Init YourViewController
    YourViewController *viewController = [[YourViewController alloc] init];
    
    // Init YourNavigationController
    UINavigationController *navigationContoller = [[UINavigationController alloc] initWithRootViewController: viewController];
    
    // Set rootViewController
    self.window.rootViewController = navigationContoller;
    
    return YES;
    
    }
    
    @end
    

    Swift 3/4 Example

    import UIKit
    
    @UIApplicationMain
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
    //1-st step
    window = UIWindow(frame: UIScreen.main.bounds)
    window?.makeKeyAndVisible()
    
    //2-nd - create a window root controller, and create a layout
    let layout = UICollectionViewFlowLayout()
    window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
    
    return true
    

    }

    0 讨论(0)
提交回复
热议问题