2014-02-03 6 views
17

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

Xcode screenshot

(Здесь the fullscreen screenshot of the storyboard показанное выше)

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; 
} 

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

UPDATE: Я попробовал следующее внушение Томми Александр со следующим кодом в 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! 

UPDATE 2: Когда я двигаю приведенный выше код к viewDidLoad 1-го представления (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>. 

UPDATE 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; 
} 
+4

Я думаю, вы могли бы добавить еще segue из вида 1 для просмотра 4 и триггера i – Jack

+0

Должен ли я ctrl-перетащить segue от контроллера навигации до последнего представления? –

+0

Не знаю .. Возможно, попробуйте это UIStoryboard * раскадровка = [UIStoryboard раскадровкаWithName: @ "Main" bundle: nil]; UIViewController * uvc = [storyboard instantiateViewControllerWithIdentifier: @ "Details"]; [self.window setRootViewController: uvc]; если нет, то сделать UINavigationController, как RootViewController и сделать IVC как его RootViewController .. Надежда, что помогает – Taseen

ответ

12

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

Вам нужно сделать следующее, чтобы достичь того, чего вы хотите:

  1. Присвоить раскадровки идентификаторов для всех контроллеров,
  2. Instantiate все три вида контроллер из раскадровки (это легкое до тех пор, как вы не делать большую часть работы инициализации в конструкторах контроллера)
  3. поместить их в массив в том же порядке, вы имеете их в раскадровке,
  4. вызова -[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:], вы увидите, что он работает сразу.

+0

Спасибо, это, по-видимому, на самом деле самое простое и быстрое решение: мне даже не нужно загружать VC, прежде чем я должен перевести/представить другой VC. –

+1

@AlexanderFarber Приветствия! ;-) Не стесняйтесь обращаться ко мне, если у вас есть еще вопросы - я был бы рад помочь. ;-) –

1

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

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

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

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

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

-Возможность ВК:

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

К сожалению, я получаю сообщение «Предупреждение: попытка представить в , чей вид не находится в иерархии окон!», И приложение не переходит к последнему виду - см. Мой обновленный вопрос –

1

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

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

Наилучший подход будет использовать для UnwindSegue ..

What are Unwind segues for and how do you use them?

UPDATE IF COMMENT не ясно

я не знаю ..

возможно попробовать это

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

если нет, то сделать UINavigationController, как RootViewController и сделать IVC как его RootViewController ..

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

+0

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

2

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

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

- (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; 
} 

UPDATE

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

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

Спасибо, но тогда пользователь не может «Выход», чтобы вернуться в TableView с выбором социальных сетей. –

+1

Используйте тот же и замените корень контроллера навигации TableViewController в обработчике выхода: 'self.navigationController.viewControllers = @ [tableViewController];' – vokilam

+0

У меня все еще есть небольшая проблема, после чего кнопка «Назад» не отображается –

3

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

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

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

enter image description here

+0

Спасибо, но мне кажется, что порядок VC - это лишь незначительная деталь (например, если вы увидите кратковременное мигание представления таблицы при запуске приложения или нет). С моим вопросом я получаю ** исходный код **, позволяя мне нажать 2 VC и перейти к третьему (что бы это ни было). –

3

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

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

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

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

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

4

Нарушение иерархии представлений всегда будет давать странное поведение.

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

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

В 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; 

} 

} 
+0

Это решение распространяет знания об одном конкретном навигационном поведении (пропуска 2 вида) на нескольких контроллерах. Разве это не могло бы объединить знания этой функции в одном месте? Было бы легче писать и легче тестировать/отлаживать. –

1

Что я делаю в одном из своих приложений, у меня есть дополнительный сеанс от 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 на экране «Сведения».

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

1

@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]; 
} 
1
- (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];} 
} 
Смежные вопросы

 Смежные вопросы