AppDelegate, rootViewController et presentViewController
je fais le tutoriel d'intégration Facebook, Je veux montrer mon Controller MainViewViewController si l'Utilisateur a un token valide pour l'état actuel sinon je veux montrer 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];
}
erreur de Console:
Warning: Attempt to present <LoginViewController: 0xb492fd0> on <MainViewViewController: 0xb1bd820> whose view is not in the window hierarchy!
Je ne veux pas utiliser un contrôleur de navigation.
5 réponses
j'ai eu le même problème. Sur la base de la réponse à cette question , j'ai ajouté [self.window makeKeyAndVisible]
juste avant presentViewController:animated:completion:
, et cela m'a corrigé.
dans votre cas, showLoginView devient
- (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];
}
présentant parfois le contrôleur de vue modale depuis la fenêtre.rootViewController peut produire le même avertissement et n'avoir aucun effet. Exemple d'une telle hiérarchie de contrôleurs de vue:
- [ Myuitable ViewController ] (modally presented by MYUIViewController )
- [ MYUIViewController ] (rootViewController of UINavigationController below)
- [ UINavigationController ] (root)
maintenant appel
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:[UIViewController new] animated:YES completion:nil];
va causer cet avertissement exact (testé à la fois sur iOS6 & 7 Sim)
Solution: Au lieu d'utiliser rootViewController-utilisez le top présenté par lui:
UIViewController *topRootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topRootViewController.presentedViewController)
{
topRootViewController = topRootViewController.presentedViewController;
}
[topRootViewController presentViewController:yourController animated:YES completion:nil];
- parfois, le clavier peut avoir été remplacé par une fenêtre avec zéro rootViewController (montrant UIAlertViews, UIActionSheets sur iPhone, etc), dans ce cas, vous devez utiliser la propriété window D'UIView.
la réponse de Stepan Generalov était la bonne pour moi dans Swift 3 !!!
Bien sûr, avec la nouvelle syntaxe etc. donc je vais le Copier ici:
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" est ma principale-vue-contrôleur de l'identifiant dans ce cas.
Je sais qu'il y a d'autres moyens, mais si vous avez besoin d'avoir des systèmes D'URL différents pour l'ouverture différentes parties de votre application, vous devez le manipuler dans AppDelegate donc c'est parfait parce que dans le
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {}
méthode, vous pouvez juste vérifier ce que url
est comme une chaîne de caractères et ensuite décider si vous exécutez le code écrit ci-dessus ou peut-être un similaire avec un identifiant différent pour un autre contrôleur de vue ( withIdentifier
)
Dans 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)
au cas où, quand vous n'utilisez pas de storyboard. Vous devez d'abord créer YourViewController. Aller À Fichier -> Nouveau -> Fichier... (ou raccourci-commande + N)
ensuite, choisissez la classe Cocoa Touch. Cliquez sur Suivant, ou entrez
que le nom de type pour votre viewController et cliquez Suivant
#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 Exemple
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
}