AppDelegate, rootViewController and presentViewController

爱⌒轻易说出口 提交于 2019-11-26 20:06:12
shebang

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];
}

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.
unixb0y

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)

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)

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

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!