2013-04-27 14 views
5

Ich habe eine App, die einen Facebook-Login beim Start implementiert, Code ähnlich wie folgt verwenden: Facebook Scrumptious Tutorial, außer mit Storyboards.Anwendung DidFinishLaunchingWithOptions wird aufgerufen, bevor Storyboards geladen werden?

Der grundlegende Kern des Codes ist, dass beim App-Start der App-Delegat überprüft, ob Sie bereits angemeldet sind, und wenn Sie es sind direkt in die Hauptansicht, und wenn nicht, fragt es die Hauptansicht um eine Login-Ansicht zu präsentieren, damit sich der Benutzer einloggen kann.

Ich habe bereits mein anderes Problem damit gelöst, dass ich der Hauptansicht im Storyboard eine andere Ansicht präsentieren kann, indem ich die Hauptansicht aus der Ansichtshierarchie erhalte und dann einen Abschnitt in der Ansicht aufrufen. Das alles funktioniert gut, aber ich habe noch ein letztes Problem bekam zu lösen:

Soweit ich bin mir dessen bewusst, die Anwendung didFinishLaunchingWithOptions Methode ist soll nach die Storyboards genannt werden gewesen voll beladen . Wenn ich jedoch in meinem Code versuche, der Hauptansicht eine andere Ansicht zu präsentieren, gibt es einen Fehler im Grunde, der besagt, dass es noch nicht geladen ist () Warnung: Versuch, < QLoginViewController: 0x955c020> on < UINavigationController: 0xa28c6e0> who Ansicht ist nicht in der Fensterhierarchie!).

Wenn ich ihm sagen, aber die Sicht nach einer Verzögerung zu präsentieren:

[self performSelector:@selector(showLoginViewAnimated:) withObject:NO afterDelay:.001]; 

(wo showLoginViewAnimated: die Methode ist, dass die Hauptansicht zeigt die Anmelde Ansicht zu präsentieren), dann funktioniert es gut.

Kann mir jemand helfen, herauszufinden, was hier schief läuft und wie ich es beheben könnte? Durchführen des Wählers mit einer Verzögerung ist offensichtlich ein schlechtes Problem zu umgehen, wie ich sich nie, wenn ein anderes Gerät wissen kann, könnte länger dauern, um die Ansichten zu laden ...

Hier ist mein AppDelegate didFinishLaunchingWithOptions Code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    // Override point for customization after application launch. 

    self.navigationController = (UINavigationController *)self.window.rootViewController; 

    // Navigation Bar Color 
    [[UINavigationBar appearance] setTintColor:[UIColor colorWithRed:255.0/255.0 green:128.0/255.0 blue:60.0/255.0 alpha:1.0]]; 


    /* Facebook Login */ // THIS IS THE RELEVANT CODE: 
    // See if we have a valid token for the current state 
    if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) { 
     // Yes, valid token exists - open the session (don't display login page) 
     [self openSession]; 
    } else { 
     // No, valid token does not exist - display the login page. 
     if ([self.navigationController isViewLoaded]) { 
      [self showLoginViewAnimated:NO]; // MY ATTEMPT TO AVOID USING THE DELAY IF POSSIBLE 
     } 
     else { 
      [self performSelector:@selector(showLoginViewAnimated:) withObject:NO afterDelay:.001]; // Delay needed to allow for storyboard loading 
     } 
    } 

    return YES; 
} 

Und hier ist der showLoginViewAnimated: Code:

- (void)showLoginViewAnimated:(BOOL)animated 
{ 
    UIViewController *topViewController = [self.navigationController topViewController]; 
    UIViewController *presentedViewController = [topViewController presentedViewController]; 

    // If the login screen is not already displayed, display it. If the login screen is 
    // displayed, then getting back here means the login in progress did not successfully 
    // complete. In that case, notify the login view so it can update its UI appropriately. 

    if (![presentedViewController isKindOfClass:[QLoginViewController class]]) { 
     if (animated) { 
      [topViewController performSegueWithIdentifier:@"ShowLoginViewAnimated" sender:self]; 
     } 
     else { 
      [topViewController performSegueWithIdentifier:@"ShowLoginViewStatic" sender:self]; 
     } 
    } 
    else { 
     QLoginViewController *loginViewController = (QLoginViewController *)presentedViewController; 
     [loginViewController loginFailed]; 
    } 
} 

In der ursprünglichen, nicht-Storyboard-Version der App, die showLoginViewAnimated: Methode wäre nicht in Anwendung didFinishLaunchingWithOptions genannt wird, bis ich hatte schon manuell die Ansichten wie so erstellt:

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
// Override point for customization after application launch. 
self.viewController = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil]; 
self.navController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 

self.window.rootViewController = self.navController; 
[self.window makeKeyAndVisible]; 

So würde ich bereits zu 100% sicher ist, dass die Ansichten vorhanden sein, bevor ich versuche, Sag ihnen, dass sie neue Ansichten präsentieren sollen. In der Storyboard-Version der App gibt es jedoch keinen Code, daher muss ich einfach darauf vertrauen, dass die Methode didFinishLaunchingWithOptions nicht aufgerufen wird, bis die Storyboard-Ansichten vollständig geladen sind - das scheint jedoch nicht zu sein der Fall. Vielleicht macht es das stattdessen asynchron? Ich habe keine Ahnung ...

Irgendwelche Ideen? Danke für jede Hilfe!

EDIT: Hier ist der Original-Code aus dem Tutorial, das funktioniert einwandfrei - und macht fast genau das gleiche, nur mit Federn. Ich habe die (BOOL) animierte Parameter zu der showLoginView Methode in meinem Code hinzugefügt, aber das ist für etwas anderes und ändert nichts (ich habe überprüft).

Hier ist das Original (nicht-Storyboard) AppDelegate didFinishLaunchingWithOptions Methode:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    // Override point for customization after application launch. 
    self.viewController = [[FBLViewController alloc] initWithNibName:@"FBLViewController" bundle:nil]; 
    self.navController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 

    self.window.rootViewController = self.navController; 
    [self.window makeKeyAndVisible]; 


    // See if we have a valid Facebook token for the current state 
    if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) { 
     // Yes, so just open the session (this won't display any UX). 
     [self openSession]; 
    } 
    else { 
     // No, display the login page. 
     [self showLoginView]; 
    } 

    return YES; 
} 

Und hier ist das Original (nicht-Storyboard) showLoginView Methode:

- (void)showLoginView 
{ 
    UIViewController *topViewController = [self.navController topViewController]; 
    UIViewController *presentedViewController = [topViewController presentedViewController]; 

    // IF the login screen is not already displayed, display it. If the login screen is 
    // displayed, then getting back here means the login in progress did not successfully 
    // complete. In that case, notify the login view so it can update its UI appropriately. 

    if (![presentedViewController isKindOfClass:[FBLLoginViewController class]]) { 
     FBLLoginViewController *loginViewController = [[FBLLoginViewController alloc] initWithNibName:@"FBLLoginViewController" bundle:nil]; 
     loginViewController.delegate = self; 
     [topViewController presentViewController:loginViewController animated:NO completion:nil]; 
    } 
    else { 
     FBLLoginViewController *loginViewController = (FBLLoginViewController *)presentedViewController; 
     [loginViewController loginFailed]; 
    } 
} 
+0

Kleiner Hinweis: Vielleicht sollten Sie Ihren TestFlight-Schlüssel besser nicht aussetzen. –

+0

Hoppla! Danke mm !! –

Antwort

9

diese Zeile didFinishLaunchingWithOptions hinzufügen:

[self.window makeKeyAndVisible]; 

vor dem Login-Code Facebook.

1

Das Hauptstoryboard ist geladen, aber die View-Controller funktionieren immer noch wie zuvor: Sie existieren erst, wenn sie benötigt werden, und dann müssen sie ihre Ansichten genauso laden wie zuvor. Ihr Code muss immer noch in einem View Controller viewDidLoad oder viewWillAppear oder was auch immer sein, als ob Sie nibs verwenden würden, indem Sie View-Controller in Code erstellen.

+0

Ich bin nicht sicher, ob das der Fall ist, da die Ansicht, die ich eine neue Ansicht präsentieren möchte, die erste Ansicht ist, und sollte daher an diesem Punkt bereits auf dem Bildschirm sein. Ich versuche auch, den gleichen Code wie das Facebook-Tutorial zu verwenden, das die Login-Logik auf dem AppDelegate (was ich mag) statt in jedem View-Controller. Ihr Code tut genau dasselbe, aber mit Nibs, und es funktioniert gut. Ich füge den ursprünglichen Code ohne Storyboard als Referenz hinzu. –

+0

Versuchen Sie nicht, dem Rahmen zu sagen, was "sein sollte". Arbeiten Sie mit dem, was das Framework tatsächlich tut. – matt

+1

Definitiv vereinbart. Mit "sollte" meinte ich, dass ich an mehreren anderen Stellen gelesen habe, dass dinFinishLaunchingWithOptions erst dann aufgerufen wird, wenn die Storyboards bereits geladen sind und die erste Ansicht auf dem Bildschirm ist (was - und korrigiere mich, wenn ich falsch liege - bedeutet das Ich sollte in der Lage sein, an dieser Stelle einen neuen Controller vorzustellen. Definitiv offen für die Arbeit mit allem, was ich brauche, um dies zum Laufen zu bringen, obwohl ich den Login-Code in der appDelegate behalten möchte, wenn ich kann. Danke. –

Verwandte Themen