2012-09-24 14 views
11

Zaimplementowałem interfejs API iOS 6 do zapisywania stanu, działa - po tym, jak opuść aplikację i uruchomię ją z powrotem na kilka milisekund, do której odtworzy się przywrócony kontroler widoku, ale zastąpiony przez główny widok kontroler wyświetlany podczas uruchamiania.iOS 6 - Zachowanie i przywracanie stanu

Ustawię za każdym razem, gdy aplikacja uruchamia główny widok głównego okna, więc to musi być problem.

Oto mój kod:

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    [self commonInitializationLaunching:launchOptions]; 
    return YES; 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    [self commonInitializationLaunching:launchOptions]; 
    return YES; 
} 

- (void)commonInitializationLaunching:(NSDictionary *)launchOptions 
{ 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 

     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
     // Override point for customization after application launch. 
     static NSString *const kKeychainItemName = @"OAuthGoogleReader"; 
     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 
     self.navController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 

     GTMOAuth2Authentication *auth; 
     auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName 
                    clientID:kClientID 
                   clientSecret:kClientSecret]; 

     self.window.rootViewController = self.navController; 

     [self.window makeKeyAndVisible]; 

     BOOL isSignedIn = [auth canAuthorize]; 
     if (isSignedIn) { 
      NSLog(@"Signed"); 
     }else{ 
      NSString *scope = @"https://www.google.com/reader/api/"; 

      GTMOAuth2ViewControllerTouch *viewController; 
      viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope 
                     clientID:kClientID 
                    clientSecret:kClientSecret 
                   keychainItemName:kKeychainItemName 
                     delegate:self 
                   finishedSelector:@selector(viewController:finishedWithAuth:error:)]; 
      [self.navController pushViewController:viewController animated:YES]; 
      //  self.window.rootViewController = viewController; 
     } 
    }); 
} 

Można zobaczyć, że w - (void) commonInitializationLaunching: (NSDictionary *) launchOptions mam ustawienie mojego okna widok korzeniowy. Nie wiem, co tam umieścić. Być może sprawdź, czy jest zapisany stan, a następnie załaduj tę metodę? Ale jak?

Dzięki!

Oto co próbowałem po poradę Roba:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    if (!self.isRestored) { 
     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    } 
    [self commonInitializationLaunching:launchOptions]; 
    [self.window makeKeyAndVisible]; 
    return YES; 
} 

z niczym w willFinishLaunching ... Ja również usunąć za pomocą kodu z mojego okna metody commonInitializationLaunching.

+0

Czy moja odpowiedź pomogła? Niektóre opinie będą świetne. – rbrown

Odpowiedz

24

Komiksy zrobią dla Ciebie większość podnoszenia ciężarów, na przykład przywracając okno. Używanie kodu nie przywróci jednak okna. Będziesz musiał trzymać się kontrolera widoku głównego za pomocą enkodera.Twój kod będzie wyglądać mniej więcej tak:

NSString * const AppDelegateRootVCKey = @"AppDelegateRootVCKey"; 

- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder { 
    [coder encodeObject:self.window.rootViewController forKey:AppDelegateRootVCKey]; 
} 

- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder { 

    // Grabs the preserved root view controller. 
    UIViewController * vc = [coder decodeObjectForKey:AppDelegateRootVCKey]; 

    if (vc) { 
     UIWindow * window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
     window.rootViewController = vc; 
     window.restorationIdentifier = NSStringFromClass([window class]); 

     // The green color is just to make it obvious if our view didn't load properly. 
     // It can be removed when you are finished debugging. 
     window.backgroundColor = [UIColor greenColor]; 

     self.window = window; 
    } 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 

    if (!self.window) { 

     UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

     // The blue color is just to make it obvious if our view didn't load properly. 
     // It can be removed when you are finished debugging. 
     window.backgroundColor = [UIColor blueColor]; 

     UIViewController *root = // However you create your root. 

     window.rootViewController = root; 
     window.restorationIdentifier = NSStringFromClass([window class]); 

     self.window = window; 
    } 

    [self commonInitializationLaunching:launchOptions]; 
    [self.window makeKeyAndVisible]; 

    return YES; 
} 

Innym haczyka uważać na to, aby upewnić się, że UINavigationController s i UITabBarController s mają identyfikatory konserwatorskich.

+0

Twoja odpowiedź wydaje się być naprawdę logiczna, chociaż nie mogłem jej wdrożyć w moim programie testowym i zostawiłem ją na jakiś czas. Dzięki za wspaniałą odpowiedź! – Devfly

6

Regeneracja stanu jest zasadniczo zintegrowana z scenorysami. Jeśli korzystasz z storyboardu, nie powinieneś tworzyć własnego okna, wyświetlać kontrolerów itp. Powinieneś pozwolić zrobić to za pomocą storyboardu. Co się dzieje, że scenorys robi całe przywrócenie stanu, a potem tworzysz nowe okno i kładziesz je na wierzchu. W takim przypadku prawdopodobnie tworzysz dwie kopie swojego interfejsu podczas każdego uruchomienia. Po prostu tego nie zauważasz.


Jeśli konstruowania cały interfejs w kodzie (nie zalecane podejście, ale działa), to trzeba ustalić, czy przywrócenie stanu zdarzyło tworzenia UI. Jest to dość prosta:

  • w twojej commonInitializationLaunching: zainicjować tylko elementy non-UI (rzeczy, które nie będą nigdy znajdować się w stanie przetrwania). To jest miejsce do obsługi rzeczy, na których elementy interfejsu użytkownika mogą polegać podczas przywracania stanu. Nie masz żadnego z nich w swoim bieżącym kodzie.

  • W application:didDecodeRestorableState: ustaw delegata aplikacji ivar na wskazujący, że stan został przywrócony.

  • W application:didFinishLaunchingWithOptions:, po uruchomieniu commonInitializationLaunching:, sprawdź swój ivar. Jeśli stan nie został przywrócony, utwórz interfejs użytkownika.

Pamiętasz, że wzór commonInitializationLaunching: istnieje tylko dla kompatybilności wstecznej z iOS 5. Jeśli nie musisz, wtedy wystarczy umieścić non-UI w willFinish i UI w didFinish (jeśli nie został przywrócony stan) .

+0

Nie używam scenorysów. – Devfly

+0

Naprawdę fajne podejście, ale wszystko, co dostaję teraz, to czarny ekran - kiedy przesuję moje '[self.windows makeKeyAndVisible]' zależnie od iVar 'isRestored', próbowałem go nawet z prostą aplikacją Master-Detail z Storyboard, i didn ' t pracował ... Czy jest coś, czego mi brakuje? – Devfly

+0

Musisz wywołać -makeKeyAndVisible we wszystkich przypadkach. Po prostu powinieneś * tworzyć * UIWindow, gdy nie przywracasz. –

Powiązane problemy