AppDelegate,rootViewController和presentViewController

时间:2012-11-17 11:35:49

标签: objective-c xcode facebook ios6 appdelegate

我正在进行Facebook集成教程,如果用户有当前状态的有效令牌,我想显示我的MainViewViewController,否则我想显示LoginViewController。

MainViewAppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
        // To-do, show logged in view
    } else {
        // No, display the login page.
        [self showLoginView];
    }
    return YES;
}
- (void)showLoginView
{
    UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"          bundle:nil];
    LoginViewController* loginViewController = [mainstoryboard      instantiateViewControllerWithIdentifier:@"LoginViewController"];
    [self.window.rootViewController presentViewController:loginViewController animated:YES completion:NULL];
}

控制台错误:

Warning: Attempt to present <LoginViewController: 0xb492fd0> on <MainViewViewController: 0xb1bd820> whose view is not in the window hierarchy!

我不想使用NavigationController。

6 个答案:

答案 0 :(得分:130)

我有同样的问题。根据{{​​3}}的答案,我在[self.window makeKeyAndVisible]之前添加了presentViewController:animated:completion:,并为我修复了此问题。

在您的情况下,showLoginView变为

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

答案 1 :(得分:36)

有时从window.rootViewController呈现模态视图控制器可能会产生相同的警告&amp;没有效果。 此类视图控制器层次结构的示例:

  1. [ MYUITableViewController ](由MYUIViewController以模态方式呈现)
  2. [ MYUIViewController ](下面的UINavigationController的rootViewController)
  3. [ UINavigationController ](root)
  4. 现在致电

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

    将导致此确切警告(在iOS6和7 Sim上都进行了测试)

    解决方案: 而不是使用rootViewController - 使用它呈现的顶部:

        UIViewController *topRootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
        while (topRootViewController.presentedViewController) 
        {
            topRootViewController = topRootViewController.presentedViewController;
        }
    
        [topRootViewController presentViewController:yourController animated:YES completion:nil];
    
    • 有时候keyWindow可能已经被带有nil rootViewController的窗口所取代(在iPhone上显示UIAlertViews,UIActionSheets等),在这种情况下你应该使用UIView的窗口属性。

答案 2 :(得分:3)

Stepan Generalov's answer对我来说是正确的 Swift 3 !!! 当然有了新的语法等,所以我将在这里复制它:

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”是我的主视图控制器的标识符。

我知道还有其他方法,但如果您需要使用不同的URL方案来打开App的不同部分,您必须在AppDelegate中处理它,所以这很完美,因为在

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

方法,您可以只检查url作为字符串的内容,然后决定是执行上面编写的代码,还是执行与其他视图控制器具有不同标识符的类似代码(withIdentifier

答案 3 :(得分:0)

在Swift 3中: -

pod 'Bolts-SDK'
pod 'Facebook-SDK', 'sdk_version'

答案 4 :(得分:0)

如果你没有使用故事板。 首先,您需要创建YourViewController。 去文件 - &gt;新 - &gt;文件...(或shortCut - 命令+ N) enter image description here

之后,选择Cocoa Touch Class。单击下一步,或单击Enter enter image description here

比viewController的类型名称,然后单击“下一步” enter image description here

#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示例

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

}

答案 5 :(得分:0)

您可以在Objective-C中像这样从根启动新的viewController

UIViewController *presenter = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;

[presenter presentViewController:yourViewController animated:YES completion:nil];

别忘了添加:

#import "AppDelegate.h"