Изменение контроллера корневого представления после загрузки приложения iOS.

Чтобы отображать мой экран входа в систему при загрузке приложения, а не после входа пользователя в систему, я решил добавить объект аутентификации в NSUserDefaults, когда пользователь входит в систему успешно. Когда приложение запускается, этот параметр auth проверяется, и контроллер представления устанавливается соответствующим образом (если пользователь авторизован, он покажет канал, если нет, он покажет экран входа в систему) В последнем случае у меня есть приложение делегат сбрасывает корневой контроллер представления на канал после того, как пользователь вошел в систему. Это плохая практика или есть лучший способ сделать это?

В делегате приложения:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary     *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    IIViewDeckController* deckController = [self generateControllerStack];
    self.rightController = deckController.rightController;
    self.centerController = deckController.centerController;

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    if([[defaults objectForKey:@"auth"] isEqualToNumber:[NSNumber numberWithInt:1]]){
        self.window.rootViewController = deckController;
    }else{
        UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                 bundle:nil];
        UIViewController* vc = [sb instantiateViewControllerWithIdentifier:@"loginViewController"];
        self.window.rootViewController = vc;
    }
    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
    return YES;
}

- (void) setRoots
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    IIViewDeckController* deckController = [self generateControllerStack];
    self.rightController = deckController.rightController;
    self.centerController = deckController.centerController;
    self.window.rootViewController = deckController;
    [self.window makeKeyAndVisible];
}

В контроллере представления входа:

- (IBAction)loginClick:(id)sender {
    if([_emailField.text length]>0&&[_passField.text length]>0){
        NSString *user = _emailField.text;
        NSString *pass = _passField.text;
        [[API sharedInstance] login:user andPass:pass onCompletion:^(NSDictionary *json){
            NSLog(@"%@", json);
            if(![json objectForKey:@"error"]){
                [API sharedInstance].authorized = 1;
                NSNumber *auth = [NSNumber numberWithInt:1];
                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                [defaults setObject:auth forKey:@"auth"];
                [defaults synchronize];

                captureYouAppDelegate *app = [[UIApplication sharedApplication] delegate];
                [app setRoots]; 
            }else{
                [API sharedInstance].authorized = 0;
            }
        }];
    }else{
        if([_emailField.text length]<1){
            [_emailField becomeFirstResponder];
        }else{
            [_passField becomeFirstResponder];
        }
    }
}

Мне интересно, есть ли способ лучше или проще, чем это сделать. Спасибо!


person Misbah Khan    schedule 14.08.2013    source источник
comment
почему бы вам не добавить простой UINavigationController как rootViewController, и вы просто не вставляете экран входа в систему в стек навигации, если пользователь уже вошел в систему. Это было бы намного проще и намного элегантнее, чем ваше текущее решение.   -  person holex    schedule 14.08.2013
comment
@holex Если панель вкладок также необходима после входа в систему, добавление UINavigationController не будет вариантом, верно?   -  person Golden Thumb    schedule 02.05.2014


Ответы (4)


Просто для уточнения. Раньше я сбрасывал rootViewController UIWindow без каких-либо проблем, но при попытке сделать это, разрешив вращение устройства, я столкнулся с некоторыми проблемами - вращение просто перестало работать.

Я нашел следующее прямо из документации Apple при попытке отладки. Ссылка ниже содержит ряд рекомендаций по работе с UIWindow. Все это связано с вращением устройства, но все же полезно знать.

Короткий ответ: используйте корневой контроллер и добавьте контроллеры дочерних представлений. Затем вы можете без проблем поменять дочерние VC.

• Вы добавили свойство UIView контроллера представления в UIWindow в качестве подпредставления.

Разработчикам не рекомендуется добавлять свойство представления любого контроллера представления в качестве подпредставления UIWindow. Контроллер корневого представления вашего приложения должен быть назначен свойству rootViewController окна приложения либо в Interface Builder, либо во время выполнения перед возвратом из приложения: didFinishLaunchingWithOptions :. Если вам нужно отображать контент из более чем одного контроллера представления одновременно, вы должны определить свой собственный контроллер представления контейнера и использовать его в качестве корневого контроллера представления. См. Создание настраиваемых контроллеров представления контейнеров.

Дополнительные сведения см. В технических вопросах и ответах.

person WCByrne    schedule 05.12.2014

Я не думаю, что сброс window.rootViewController - плохая практика. Однако нет необходимости воссоздавать окно.
Если вы не хотите использовать предыдущий контроллер представления, просто замените rootViewController окна новым контроллером представления. Если вы действительно хотите вернуться к своему предыдущему контроллеру представления, используйте -presentViewController: animated: completion:, чтобы представить, что ваш контроллер представления может быть лучшей альтернативой.

person liuyaodong    schedule 14.08.2013
comment
Простая замена не позволяет мне устанавливать свойства IIViewDeckController. - person Misbah Khan; 14.08.2013
comment
Я согласен с этим, изменение rootViewController во время выполнения - очень плохой кодовый шаблон. - person holex; 14.08.2013
comment
@holex Не могли бы вы объяснить, почему это очень плохой шаблон кода? Спасибо! - person Golden Thumb; 02.05.2014
comment
@liuyaodong У вас есть предложения, как освободить предыдущий rootViewController, если он мне никогда не понадобится? Спасибо! - person Golden Thumb; 02.05.2014
comment
@GoldThumb, буквально не существует такой ситуации, которая требовала бы от разработчика изменения rootViewController во время выполнения, буквально все можно сделать, не касаясь UIWindow. с другой стороны, учитывая, что он был установлен во время запуска, и согласно логике жизненного цикла приложения, приложение не должно возвращаться почти к началу своего собственного жизненного цикла. однако это можно сделать свободно, но такая процедура указывает на то, что слой представления (и «дерево» навигации) был спроектирован плохо. - person holex; 02.05.2014
comment
Кто-нибудь знает что-нибудь о том, почему ротация устройства нарушена, если вы просто установите rootVC? Раньше я заменял корень, отлично работает, но до сих пор никогда не пробовал разрешить вращение. - person WCByrne; 05.12.2014
comment
Это плохой шаблон, потому что 1) как упоминалось ранее, контроллер представления на самом деле не освобожден 2) если он действительно не освобожден, с этим контроллером представления все еще происходит много вещей, включая получение уведомлений и, следовательно, некоторые случайные методы, вызываемые, пока вы не действительно осознаю это. 3) в зависимости от того, как вы это делаете, но обычно у вас не будет обычного хорошего UX перехода между экранами, к которому привыкли пользователи [с анимацией и быстрым входом в контекст / идею другого приложения]. - person Fawkes; 20.10.2015

Нет необходимости повторно выделять окно, вы можете напрямую установить это

window.rootViewController = yourVC;
person Divyam shukla    schedule 14.08.2013

Шаг за шагом я показываю передовой опыт использования rootviewcontroller с помощью UINavigationController.

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

    self.splash = [[SplashViewController alloc] initWithNibName: @"SplashViewController" bundle: nil];  
    self.window.rootViewController = self.splash;  
    [self.window makeKeyAndVisible];  
    DLog(@"finished initializing .....");  
    [self setRootViewController];  

    return YES;  
}



- (void) setRootViewController  
{  
    DLog(@"setRootViewController");  
    if (self.sessionManager.isLoggedIn)  
    {  
            [self navigateToHomeController];  

    } else {  
            [self navigateToLoginController];  
      }  
}


- (void) navigateToHomeController  
{  
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"kStoryBoard" bundle: nil];  
    UINavigationController* homeNavigationController =  [storyboard instantiateViewControllerWithIdentifier:@"kHomeNavController"];  
    NSArray* controllers = [homeNavigationController viewControllers];  
    if([controllers lastObject])  
    {  
        if ([[controllers objectAtIndex:0] isKindOfClass:[HomeViewController class]]) {  
            HomeViewController* homeController = (HomeViewController*) [controllers objectAtIndex:0];  
            self.window.rootViewController = [[OLNavigationViewController alloc] initWithRootViewController: homeController]; 
        }  
    }  
}



- (void) navigateToLoginController  
{  
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"kStoryBoard" bundle: nil];  
    UINavigationController* loginNavigationController = [storyboard instantiateViewControllerWithIdentifier:@"kLoginNavController"];  
    if ([loginNavigationController isKindOfClass:[OLLoginViewController class]]) {  
        OLLoginViewController* loginController = (OLLoginViewController*) loginNavigationController;  
        loginController.shouldHideToolBar = YES;  
        self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController: loginController];  
    }
}
person TheCodeTalker    schedule 07.07.2016