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

ViewDidLoad, вызываемый перед завершением подготовкиForSegue

У меня создалось впечатление, что viewDidLoad будет называться ПОСЛЕ завершения подготовкиForSegue. Это даже то, как Гегарти преподает свой класс Стэнфорда (совсем недавно, в феврале 2013 года).

Однако в первый раз сегодня я заметил, что viewDidLoad был вызван до того, как завершилась подготовкаForSegue. Поэтому свойства, которые я устанавливал в prepareForSegue, недоступны для целевогоViewController в методе viewDidLoad для адресатов.

Это противоречит ожидаемому поведению.

UPDATE

Я только что понял, что происходит. В моем destinationViewController у меня был настраиваемый сеттер, который будет перезагружать tableView каждый раз, когда обновляется "модель":

DestinationViewController    
- (void)setManagedObjectsArray:(NSArray *)managedObjectsArray
    {
        _managedObjectsArray = [managedObjectsArray copy];
        [self.tableView reloadData];
    }

Оказывается, поскольку destinationViewController является подклассом UITableViewController... вызов self.tableView заставляет загрузку представления. Согласно документации Apple, вызов свойства view контроллера вида может заставить просмотр загружаться. Представление UITableViewController - это tableView.

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html

Следовательно, в prepareForSegue следующая строка заставляла загружать представление destinationViewController:

vc.managedObjectsArray = <custom method that returns an array>;

Чтобы устранить проблему, я изменил пользовательский установщик модели destinationViewController на:

- (void)setManagedObjectsArray:(NSArray *)managedObjectsArray
    {
        _managedObjectsArray = [managedObjectsArray copy];
        if ([self isViewLoaded]) {
            [self.tableView reloadData];
        }
    }

Это только перезагружает tableView, если tableView находится на экране. Таким образом, не заставляя просмотр загружаться во время подготовки к работе.

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

4b9b3361

Ответ 1

В прошлом я столкнулся с подобными путаницами. Общие эмпирические правила, которые я узнал:

  • prepareForSegue вызывается перед назначением VC viewDidLoad
  • viewDidLoad вызывается только после загрузки всех выходов
  • Не пытайтесь ссылаться на любые точки назначения VC в исходном VC prepareForSegue.

Еще один урок, который выучил в отношении prepareForSegue, заключается в том, чтобы избежать избыточной обработки. Например, если вы уже выделили ячейку tableView в VC через раскадровку, вы можете столкнуться с аналогичным состоянием гонки, если попытаетесь обработать BOTH tableView: didSelectRowAtIndexPath и prepareForSegue. Этого можно избежать, используя либо ручной отступ, либо отказаться от любой обработки в файле didSelectRowAtIndexPath.

Ответ 2

Спасибо за обмен, помогли мне разобраться в моей проблеме.

В моем случае, destinationViewController - это UITabBarController и изменение его viewControllers Array вызвало viewDidLoad:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    UITabBarController *tabBarController = segue.destinationViewController;
    tabBarController.viewControllers = ...
    tabBarController.something = something;
}

в viewDidLoad мне нужно было установить атрибут something, поэтому мне пришлось его переместить:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    UITabBarController *tabBarController = segue.destinationViewController;
    tabBarController.something = something;
     tabBarController.viewControllers = ...
}

Ответ 3

простым решением является размещение

[self.tableView reloadData];

в viewWillAppear:

Ответ 4

Думаю, я бы добавил небольшое объяснение, что произошло здесь:

prepareForSegue вызывается перед отображением представления

viewDidload вызывается при первом обращении к виду.

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

Обычно поток:

  • preformSegue
  • prepareForSegue
  • ViewController добавляется в иерархию
  • viewDidload.

Но что, вероятно, произошло в вашем случае:

  • preformSegue
  • prepareForSegue
  • | - В prepareForSegue вы получаете доступ к view
  • | - view автоматически загружается = > viewDidload вызывается
  • Возврат из performSegue
  • В иерархию добавлен ViewController, no viewDidload (уже вызванный)

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