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 находится на экране. Таким образом, не заставляя просмотр загружаться во время подготовки к работе.
Если кто-то возражает против этого процесса, поделитесь своими мыслями. В противном случае я надеюсь, что это предотвратит долгую бессонную ночь для кого-то.
Ответы
Ответ 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
может быть запущен ранее.