Подтвердить что ты не робот

Как пропустить 2 представления при использовании контроллера навигации

В Xcode 5.0.2 я создал приложение для iPhone (полное приложение code на GitHub, запустите pod install один раз - для SDWebImage), в котором отображается список социальных сетей (Facebook, Google+ и т.д.), затем - в другом виде - UIWebView, отображающий веб-страницу OAuth2, а затем третье представление с аватаром пользователя и информацией (имя, фамилия и т.д.):

Xcode screenshot

(Здесь полноэкранный снимок экрана раскадровки, показанный выше)

enter image description here

Прежде чем отображать аватар пользователя и данные в последнем представлении, я сохраняю данные пользователя в NSUserDefaults.

Мой вопрос:, когда пользователь запускает приложение в следующий раз и уже есть данные пользователя в NSUserDefaults - как я могу пропустить первые 2 представления и отобразить (без какой-либо анимации) последний вид с данными пользователя?

Я добавил следующий код в AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *key = [defaults objectForKey:@"key"];
    User *user = [User loadForKey:key];

    if (user) {
        UINavigationController *nc = (UINavigationController*)self.window.rootViewController;
        // XXX how to load the last view here? XXX
    }

    return YES;
}

и может видеть, что пользовательские данные загружаются в порядке, но я не понимаю, как перейти к последнему виду (особенно потому, что большая часть пользовательского интерфейса определена в раскадровке)?

ОБНОВЛЕНИЕ: Я пробовал следовать предложению Томми Александра (спасибо!) со следующим кодом в AppDelegate.m (а также присвоенный Details StoryboardID до последнего представления):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *key = [defaults objectForKey:@"key"];
    User *user = [User loadForKey:key];

    if (user) {
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *uvc = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
        NSLog(@"XXX uvc=%@ user=%@", uvc, user);
        [self.window.rootViewController presentViewController:uvc animated:YES completion:nil];
    }

    return YES;
}

и в то время как последний вид (UserViewController с аватаром пользователя и деталями), похоже, полностью создан, я получаю следующее предупреждение и приложение не переходит к последнему виду:

MyAuth[3917:70b] XXX uvc=<UserViewController: 0x8acbac0> user=
VK
59751265
Alexander
Farber
1945522
http://cs319319.vk.me/v319319265/b7df/TnyKeffL_mU.jpg
0
MyAuth[3917:70b] Warning: Attempt to present <UserViewController: 0x8acbac0> on <UINavigationController: 0x8bb3a30> whose view is not in the window hierarchy!

ОБНОВЛЕНИЕ 2:. Когда я перемещаю вышеуказанный код в viewDidLoad первого вида (MasterViewController.m, где пользователь может выбрать социальную сеть), затем я получаю другое предупреждение:

MyAuth[1358:70b] XXX uvc=<UserViewController: 0x8a97430> user=
FB
597287941
Alexander
Farber
Bochum, Germany
http://graph.facebook.com/597287941/picture?type=large
0
MyAuth[1358:70b] Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x8a893e0>.

ОБНОВЛЕНИЕ 3: Спасибо за ценные ответы! Я в конечном итоге использовал предложение Леонтия Дериглазова:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UIViewController *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"Master"];
    //UIViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"Login"];
    UIViewController *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"User"];

    User *user = [User load];
    NSArray *controllers = (user ? @[vc1, vc3] : @[vc1]);

    UINavigationController *nc = (UINavigationController *)self.window.rootViewController;
    [nc setViewControllers:controllers];

    return YES;
}
4b9b3361

Ответ 1

Вкратце, наиболее простым решением является использование -[UINavigationController setViewControllers:animated:].

Для достижения желаемого результата необходимо выполнить следующие действия:

  • присваивать идентификаторы раскадровки всем вашим контроллерам,
  • создать экземпляр всех трех контроллеров представления из панели рассказов (это легкий вес, если вы не выполняете большую часть инициализации в конструкторах контроллера).
  • помещаем их в массив в том же порядке, что и у вас в раскадровке,
  • вызов -[UINavigationController setViewControllers:] с массивом в качестве первого аргумента.

Что это. Код в вашем -[AppDelegate application:didFinishLaunchingWithOptions:] может выглядеть так (после проверки вашего условия прохода, конечно):

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"MyAuth"]; //if you assigned this ID is storyboard
UIViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"Login"];  //if you assigned this ID is storyboard
UIViewController *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
NSArray *controllers = @[vc1, vc2, vc3];
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController setViewControllers:controllers];

Если вы введете только это в -[AppDelegate application:didFinishLaunchingWithOptions:], вы увидите, что он работает немедленно.

Ответ 2

Искажение иерархии просмотров всегда дает странное поведение.

Используя нижеприведенный подход, пользователь не сможет заметить, что LoginViewController представлен, а затем мы нажали на экран Detail.

Этот подход всегда работал у меня

В файле LoginViewController.m

- (void)viewDidLoad
{

if (user) {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UserViewController *userViewController = [storyboard instantiateViewControllerWithIdentifier:@"Details"];


[self.navigationController pushViewController:listViewVC animated:YES];

    }
}

В файле UserViewController.m

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];

if (user) {

    self.navigationItem.hidesBackButton = YES;

}

}

Ответ 3

Я думаю, что ваша проблема начинается с вашей начальной настройки раскадровки. Я бы использовал что-то вроде изображения ниже.

Я бы сделал User View controller мой контроллер корневого представления и представил контроллеры виджетов входа в моду с анимацией или без нее.

После успешного входа в систему будет довольно удобно отклонить контроллеры представления. И если пользователь выйдет позже, вам просто нужно будет снова представить контроллеры просмотра входа.

enter image description here

Ответ 4

Я думаю, вы можете это сделать:

if (hasUser) {
    MyFirstViewController *firstViewController = [myStoryboard instantiateViewControllerWithIdentifier:@"FirstViewControllerStoryboardId"];
    SecondViewController *secondViewController = [myStoryboard instantiateViewControllerWithIdentifier:@"SecondViewControllerStoryboardId"];

    [myNavigationController pushViewController:firstViewController animated:NO];
    [myNavigationController pushViewController:secondViewController animated:YES];
}

Таким образом, у вас не будет анимации, и навигационный стек будет соблюден. Измените "анимированное" логическое значение, чтобы воспроизвести анимацию (ы).

Надеюсь, что это поможет!

Ответ 5

Попробуйте дать вашему последнему UIViewController значение StoryBoardID в инспекторе атрибутов в IB. Затем, как только вы определите, есть ли у пользователя пользователь NSUSerDefault:

-Получить ссылку на раскадровку:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

-Использовать экземпляр вашего последнего контроллера представления (не забудьте импортировать последний файл contorllers просмотра .h):

UIViewController *myController = [storyboard instantiateViewControllerWithIdentifier:@"StoryBoardID"];

-Представляем VC:

[self presentViewController:myController animated:YES completion:nil]; 

Ответ 6

Используйте это:

[self.presentingViewController dismissViewControllerAnimated:NO completion:^{
    [self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}];

Лучшим подходом будет использование UnwindSegue.

Что такое Unwind segues и как вы их используете?

ОБНОВЛЕНИЕ, ЕСЛИ КОММЕНТАРИЙ НЕ ЯВЛЯЕТСЯ

Я не знаю..

возможно, попробуйте это

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *uvc = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
[self.window setRootViewController:uvc];

если нет, тогда сделайте UINavigationController как rootViewController и сделайте ivc в качестве его rootViewController..

Надеюсь, что поможет

Ответ 7

В соответствии с вашим рабочим процессом экрана у вас есть контроллер навигации, и в него вставляются другие контроллеры.

Таким образом, логика проста: если пользователь кэшируется задает детали контроллер представления как корень вашего контроллера просмотра навигации, то ничего не делать (используется раскадровка по умолчанию).

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UINavigationController *nc = (UINavigationController*)self.window.rootViewController;

    if (hasUser) {
        UIViewController *vc = [nc.storyboard instantiateViewControllerWithIdentifier:@"DetailsViewController"];
        nc.viewControllers = @[vc];
    }

    return YES;
}

ОБНОВЛЕНИЕ

Если вам нужно вернуться к предыдущим контроллерам представлений (например, из деталей в таблицу), вы можете установить всю навигационную иерархию в контроллере навигации:

UINavigationController *nc = (UINavigationController*)self.window.rootViewController;
if (hasUser) {
    UIViewController *vc = [nc.storyboard instantiateViewControllerWithIdentifier:@"DetailsViewController"];
    [nc pushViewController:vc animated:NO];
}

Ответ 8

Что я делаю в одном из моих приложений, у меня есть дополнительный переход из rootViewController на экран, который я хочу пропустить (в вашем примере от MyAuth до деталей). Затем, когда я показываю UINavigationController, я также устанавливаю переменную в rootViewController, указывающую, хочу ли я перейти к другому экрану. Наконец, в viewDidLoad: контроллера вида я делаю чек:

// Check if we want to skip to another screen
if (self.skipToDetails == YES) {
    [self performSegueWithIdentifier:@"detailsView" sender:nil];
}

Если вы отключите анимацию для этого segue в файле раскадровки, пользователь не увидит первый экран вообще.

Кроме того, вам нужно установить hidesBackButton на YES на экране сведений.

Изменить: "unbalanced calls to begin/end" происходит, когда вы переходите к другому VC (либо push или modal) из оригинального (rootViewController) VC в viewDidLoad:. Перемещение кода на viewDidAppear: должно помочь.

Ответ 9

@Alexander, пожалуйста, проверьте скриншот, вы можете управлять контроллером следующим образом:

enter image description here

И используйте следующий код в контроллере пользовательского вида:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *key = [defaults objectForKey:@"key"];
User *user = [User loadForKey:key];

if (!user) {
 MasterViewController *loginController = [self.storyboard instantiateViewControllerWithIdentifier:@"MasterViewController"];
[self presentViewController:masterController animated:YES completion:nil];
}

Ответ 10

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *key = [defaults objectForKey:@"key"];
    User *user = [User loadForKey:key];

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

    if (hasUser) {
        UIViewController *viewcon = [navcon.storyboard instantiateViewControllerWithIdentifier:@"DetailsViewController"];
        [navcon pushViewController:viewcon animated:NO]; }   
}
else
   {
       UIViewController *viewcon = [navcon.storyboard instantiateViewControllerWithIdentifier:@"UserViewController"];
       [navcon pushViewController:viewcon animated:NO];}
}