UINavigationController popToRootViewController, а затем сразу же нажмите новый вид - PullRequest
23 голосов
/ 05 июня 2009

У меня есть tabBarController с двумя вкладками, первая из которых содержит экземпляр NavigatorController. NavigatorController запускается с помощью пользовательского viewController "peersViewController", в котором перечислены все сетевые одноранговые узлы в tableView. После выбора однорангового узла экземпляр «FilesListViewController» (который перечисляет файлы в каталоге c: \) помещается в стек navigationController.

В этом файле ListViewController у меня есть кнопка, позволяющая ему перемещаться в директорию документов. Для этого я подключил интерфейс для вызова метода пути gotoDirectory: (NSString *) в rootViewController:

- (void)gotoDirectory:(NSString*)path {
     [[self navigationController] popToRootViewControllerAnimated:YES];
     NSArray *files = [self getFilesFromPeerAtPath:path];
     FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
     [[self navigationController] pushViewController:filesVC animated:YES];
     [filesVC release];
}

Однако, когда я нажимаю эту кнопку, navigationController действительно выскальзывает из моего представления в контроллер корневого представления, но затем не открывается экземпляр FilesListViewController, который я создал. Из журнала я знаю, что пользовательский метод initWithFiles действительно был вызван, и сетевые компоненты действительно получали имена файлов.

Что-то еще не так в этом. Я попытался нажать на вторую вкладку, а затем вернуться к первой вкладке, и хуала! имена файлов, которые мне нужны были там. Похоже, что данные и filesListViewController действительно были помещены в стек navigatorController, но дисплей не обновился, а застрял на экране rootViewController (peersViewController).

Я что-то не так делаю?

-. Бен

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

- (void)gotoDirectory:(NSString*)path {
     PeersListViewController *rootViewController = (PeersListViewController*)[[[self navigationController] viewControllers] objectAtIndex:0];
     [[self navigationController] setViewControllers:[NSArray arrayWithObject:rootViewController]];
     FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
     [[self navigationController] pushViewController:filesVC animated:YES];
     [filesVC release];
}

Не похоже, что навигационный контроллер должен быть обойден таким образом, и мне, вероятно, придется выпустить все контроллеры viewController, которые были в исходном стеке. Это, однако, работает на симуляторе iphone 3.0.

Если я использую этот код, как следует обращаться с выпуском памяти? я должен получить оригинальный NSArray viewcontrollers и выпустить все?

Ответы [ 6 ]

83 голосов
/ 11 декабря 2010

Проблема и решение этой проблемы на самом деле очень просты.

Вызов [self.navigationController popToRootViewControllerAnimated:YES] устанавливает self.navigationController на nil. Когда вы впоследствии звоните [self.navigationController pushViewController:someOtherViewController], вы фактически отправляете сообщение на номер nil, который ничего не делает.

Чтобы обойти это, просто установите локальную ссылку на navigationController и используйте вместо этого:

UINavigationController * navigationController = self.navigationController;
[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:someOtherViewController animated:YES];

Как заявил Джейсон, popToRootViewController должен выполняться без анимации, чтобы это работало правильно.

Спасибо, что обратились к jpimbert на форумах Apple за указание на это.

10 голосов
/ 17 сентября 2009

У меня очень похожая проблема (но без использования вкладки).

Я получил три viewController : main(root), форму и результат. когда стек UINavigationController равен

"main -> result"

на btnClick Я делаю popToRootViewControllerAnimated, а затем нажатие formViewCtrl. чтобы иметь

"main -> form"

заголовок навигационной панели и метка кнопки возврата верны, и вызывается событие formViewCtrl. НО, я все еще вижу основной вид.

Вот мое "решение"

После некоторого теста я обнаружил, что без анимации для перехода к rootViwCtrl прекрасно работает . Поэтому я использую анимацию только для нажатия viewCtrl.

iPhone 3.0, обнаружена проблема на устройстве и симуляторе.

Если я получу что-то новое, я буду обновлять / комментировать свой пост.

4 голосов
/ 10 мая 2012

Я вижу, что этот вопрос о том, чтобы получить доступ к корню и затем нажать новый ViewController, довольно распространен, и этот пост просматривается очень часто, поэтому я хотел добавить свой бит, чтобы помочь другим новым парням, особенно тем, кто использует Xcode 4 и раскадровка.

В Xcode 4 у вас есть раскадровка. Допустим, у вас есть следующие контроллеры представления: HomeViewController, FirstPageViewController, SecondPageViewController. Удостоверьтесь, что щелкнули по каждому из них и назвали их идентификаторы, перейдя в Панель утилит-> Инспектор атрибутов. Мы скажем, что они названы Дом, Первый и Второй.

Вы находитесь дома, затем вы переходите к первому, затем вы хотите иметь возможность перейти ко второму и нажать кнопку «назад», чтобы вернуться к главному. Для этого вы хотите изменить свой код в FirstPageViewController.

Чтобы развернуть пример, создайте кнопку в FirstPageViewController в раскадровке. Перетащите эту кнопку с помощью Ctrl в FirstPageViewController.m. Там следующий код даст желаемый результат:

    // Remember to add #import "SecondPageViewController.h" at the top
    SecondPageViewController *secondView = [self.storyboard instantiateViewContorllerWithIdentifier:@"Second"];
    UINavigationController *navigationController = self.navigationController;
    NSArray *array = [navigationController viewControllers];
    // [array objectAtIndex:0] is the root view controller
    NSArray *viewControllersStack = [NSArray arrayWithObjects:[array objectAtIndex:0], secondView, nil];
    [navigationController setViewControllers:viewControllersStack animated:YES];

По сути, вы захватываете контроллеры представления, размещаете их в стеке в нужном вам порядке, а затем контроллер навигации использует этот стек для навигации. Это альтернатива толчку и хлопанию.

1 голос
/ 22 марта 2012

На самом деле вы можете сохранить анимацию «Назад», а затем анимацию «Вперед», фактически задерживая анимацию нажатия до завершения анимации поп-музыки. Вот пример:

(Примечание. У меня в appDelegate есть переменная NSString с именем «transitionTo», для которой изначально задано значение «@» ») ... Сначала установите для этой переменной значение NSString, которое вы сможете обнаружить позже. Затем вставьте контроллер, чтобы получить хороший переход экрана обратно в корень:

appDelegate.transitionTo = @"Another";
[detailNavigationController popToRootViewControllerAnimated:YES];

Затем внутри класса rootviewcontroller используйте метод viewDidAppear:

-(void)viewDidAppear:(BOOL)animated
{
    AppDelegate *appDelegate =(AppDelegate*) [UIApplication sharedApplication].delegate;
    if([appDelegate.transitionTo isEqualToString:@"Another"])
    {
        [self transitionToAnotherView];
        appDelegate.transitionTo = @"";
    }
}

-(void)transitionToAnotherView
{
    // Create and push new view controller here
    AnotherViewController *controller = [[AnotherViewController alloc] init];

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:nil action:nil];
    [self.navigationItem setBackBarButtonItem:backButton];

    [[self navigationController] pushViewController:controller animated:YES];
}

Так что, по сути, поп в корень ... когда переход заканчивается в "viewDidAppear" ... затем нажмите следующий вид. Я случайно сохранил переменную, которая сообщит вам, к какому виду вы хотите перейти (с @ "", означающим не выполнять переход в том случае, если я хочу остаться на этом экране).

1 голос
/ 10 октября 2011

Ответ Ника Стрита отлично работает, если вы хотите использовать popToRootViewController, а затем нажать еще один VC.

VC1 -> VC2 -> VC3: нажмите кнопку «Назад» из VC3 => VC2, затем VC1, здесь OK

Однако, когда VC1 толкает VC2, что, в свою очередь, толкает VC3, то возврат обратно к VC1 напрямую из VC3 не работает должным образом:

Я реализовал в VC3 -(void)viewWillDisappear:(BOOL)animated:

-(void)viewWillDisappear:(BOOL)animated{

    ...
    [self.navigationController popToRootViewControllerAnimated:YES];
}

Я также пытался реализовать это в «кнопке назад», тот же результат: при нажатии кнопки «Назад» из VC3, чтобы вернуться в VC1: он ломается. Фактическим VC является VC1, но панель навигации по-прежнему VC2. Играя с другими комбинациями, я получаю navBar VC1 на VC2. Всего беспорядка.

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

В VC3:

-(void)viewWillDisappear:(BOOL)animated {

    [super viewWillDisappear:animated];
    // notify VC2
    [[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self];
}

В VC2:

-(void)viewDidLoad {

    ...

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(backFromV3)
                                                 name:@"BackFromV3"
                                               object:nil];
}

-(void)backFromV3{
    [NSTimer scheduledTimerWithTimeInterval:0.5 
                                 target:self
                               selector:@selector(backToRootViewController)
                               userInfo:nil
                                repeats:NO];
}

-(void)backToVC1 {
    self.navigationItem.rightBarButtonItem = nil;
    [self.navigationController popToRootViewControllerAnimated:YES];
}

Конечно, сделайте необходимую уборку.

Таймер здесь критичен. Если 0, он ломается. 0.5 вроде бы в порядке.

Это прекрасно работает для меня. Немного тяжелый, но я не смог найти ничего, что могло бы помочь.

1 голос
/ 29 октября 2009

Я нашел обходной путь, но не могу объяснить, почему он работает: 1. Сначала нажмите на нужный контроллер. 2. Затем перейдите к тому, который вы хотите.

Это совершенно нелогично, но в моем случае это работает. Просто чтобы прояснить ситуацию, я использую это в следующем сценарии: Первый экран -> Переход к экрану загрузки -> Второй экран Когда я на втором экране, я не хочу, чтобы экран загрузки находился в стеке, а когда я нажимаю назад, я должен перейти на первый экран.

С уважением, Веско Колев

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...