web-dev-qa-db-ja.com

AppDelegate、rootViewController、presentViewController

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を使用したくありません。

38
Boris-V

同じ問題がありました。 この質問 への回答に基づいて、[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];
}
131
shebang

Window.rootViewControllerからモーダルView Controllerを表示すると、同じ警告が生成され、効果がない場合があります。このようなView Controllerの階層の例:

  1. [MYUITableViewController](MYUIViewControllerによりモーダルで提示)
  2. [MYUIViewController](以下のUINavigationControllerのrootViewController)
  3. [INavigationController](ルート)

呼び出し中

[[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のウィンドウプロパティを使用する必要があります。
36

Stepan Generalovの答え は、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スキームを使用する必要がある場合は、AppDelegateで処理する必要があります。

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

メソッドでは、urlが文字列として何であるかを確認してから、上記のコードを実行するか、他のView Controller(withIdentifier)の異なる識別子を持つ同様のコードを実行するかを決定できます。

3
unixb0y

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
Jay Mehta

ケースでは、ストーリーボードを使用していないとき。まず、YourViewControllerを作成する必要があります。 Go File-> New-> File ...(またはshortCut-command + 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

}

0
Alex Kolovatov