#iphone #ios #uiviewcontroller #uinavigationcontroller
#iPhone #iOS #uiviewcontroller #uinavigationcontroller
Вопрос:
Вот шаг.
- У меня есть подкласс UIViewController, который что-то делает в своих методах viewWillAppear и viewDidAppear.
- Я хочу вложить этот контроллер представления в UINavigationViewController.
- В зависимости от сложности иерархии представлений два метода
viewWillAppear
иviewDidAppear
моего контроллера могут не вызываться.
Что мне тогда делать, чтобы убедиться, что эти два метода всегда вызываются независимо от моей иерархии представлений?
Пример «сложной» иерархии представлений:
UIViewController subclass containing a UITabBarController
|_ Each tab containing a UINavigationViewController
|_ Each UINavigationController controller containing a custom UIViewController
Когда вы представляете TabBarController в качестве модального представления viewWillAppear
, viewDidAppear
вызываются методы и TabBarController, но не методы пользовательских UIViewControllers, вложенных в UINavigationViewControllers .
Ответ №1:
ПРИМЕЧАНИЕ: это было написано в 2013 году. Изменения в том, как iOS обрабатывает иерархии представлений в настоящее время, могут сделать это решение бесполезным и / или опасным. Поэтому используйте на свой страх и риск.
Оригинальный ответ При вложении пользовательского UIViewController в UINavigationController методы viewWillAppear и viewDidAppear пользовательского ViewController могут не вызываться в зависимости от сложности иерархии вашего view controller (например, модальные представления, контроллер навигации внутри контроллера представления вкладок …). Итак, если вы окажетесь в такой ситуации, что вы можете сделать, чтобы обеспечить вызов этих двух методов?
Ответ…
Используйте методы UINavigationControllerDelegate
Это очень элегантный метод для реализации, поскольку он не зависит от каких-либо предположений относительно того, когда контроллер будет загружен контроллером навигации.
Доступно два метода:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
Вот как изменится код.
Вам необходимо объявить, что ваш CustomViewController реализует протокол UINavigationControllerDelegate:
@interface CustomViewController : UIViewController <UINavigationControllerDelegate>
Вам необходимо установить свой CustomViewController в качестве делегата UINavigationController, где вы его инициализируете.
Наконец, вы также должны добавить свою пользовательскую реализацию методов UINavigationControllerDelegate в свою реализацию класса CustomViewController. Например, вы можете реализовать navigationController:willShowViewController:animated:
метод так, чтобы:
- когда UINavigationController собирается показать сам контроллер представления, вызывается ваш метод viewWillAppear
- когда UINavigationController собирается показать другой контроллер представления, делегат UINavigationController устанавливается на этот другой контроллер представления, при условии, что этот контроллер представления реализует метод UINavigationViewControllerDelegate .
Элемент списка
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([viewController isEqual:self]) {
[viewController viewWillAppear:animated];
} else if ([viewController conformsToProtocol:@protocol(UINavigationControllerDelegate)]){
// Set the navigation controller delegate to the passed-in view controller and call the UINavigationViewControllerDelegate method on the new delegate.
[navigationController setDelegate:(id<UINavigationControllerDelegate>)viewController];
[[navigationController delegate] navigationController:navigationController willShowViewController:viewController animated:YES];
}
}
И navigationController:didShowViewController:animated:
могут быть реализованы просто следующим образом:
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
if ([viewController isEqual:self]) {
[self viewDidAppear:animated];
}
}
Преимущество этого подхода заключается в том, что вы полагаетесь исключительно на то, как должен работать UINavigationViewController, и вы совершаете свои вызовы в нужное время. Это также позволяет вам передавать делегирование при перемещении вверх и вниз по иерархии навигационного контроллера прямо перед вызовом метода viewWillAppear.
Опять же, для простой иерархии это может не потребоваться. Но если вы когда-нибудь окажетесь в ситуации, когда ваши viewWillAppear
viewDidAppear
методы and не вызываются, теперь вы знаете, что делать…
Комментарии:
1. У вас есть источник для этого утверждения? Я почти уверен, что в этой ситуации я использую viewWillAppear, и он вызывается. (хотя сейчас пойду и проверю!)
2. @jrturton Это особенно актуально, когда вы начинаете играть с контроллерами модального представления и более сложной иерархией. И решение остается общим: если ваш метод не вызывается, используйте протокол UINavigationControllerDelegate вместо прямых вызовов
3. @jrturton Я сделал свое заявление немного менее строгим, чтобы отразить тот факт, что если методы не вызываются, вы можете использовать технику делегирования вместо прямых вызовов.
4. Вы заставили меня волноваться там на минуту!
5. @jrturton извините… Я переформулирую проблему и решение прямо сейчас, чтобы не пугать людей, как я напугал вас…
Ответ №2:
Одна из причин, по которой это произойдет, заключается в том, что вы переопределяете viewDidAppear:
в своем UINavigationController
подклассе и не вызываете [super viewDidAppear:animated];
…
Комментарии:
1. Это именно так. Так много ответов предлагают вызывать viewWillAppear / viewDidAppear вручную из другого содержащего контроллера. В моем случае более пристального взгляда на эти переопределения было достаточно, чтобы увидеть, где я забыл вызвать суперреализацию.
Ответ №3:
Сейчас 2015 год, и вам, вероятно, не нужно использовать методы UINavigationControllerDelegate, как в принятом ответе. Просто внимательно проверьте свой код, если у вас есть какая-либо опечатка или ошибка копирования / вставки.
В последнее время я столкнулся с проблемой, которая viewDidAppear
больше не вызывается после некоторого копирования / вставки. Прочитав ответ @Yar, я выполнил поиск viewDidAppear
в своем коде и обнаружил, что [super viewDidAppear:animated];
он был ошибочно вызван viewWillAppear
:
-(void)viewWillAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//... ^^^
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// this is never called :(
}
Просто поделитесь этим выводом здесь на случай, если люди столкнутся с такой же проблемой.
Ответ №4:
это должно быть сделано следующим образом:
См. (* 1) редактировать
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
CustomViewController *controller = [[CustomViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release];
self.window.rootViewController = navController; //(*1)
[self.window makeKeyAndVisible];
[navController release];
return YES;
}
Комментарии:
1. ОК. И появляется ли CustomViewController? Если нет, попробуйте
CustomViewController *controller = [CustomViewController new];
вместоCustomViewController *controller = [[CustomViewController alloc] initWithNibName:nil bundle:nil];
2. Да, все выглядит нормально… Однако суть вопроса не в этом. Контроллер всегда отображается, но при вложении в UINavigationController методы viewWillAppear и viewDidAppear не вызываются.
3. О, хорошо. В этом случае я не знаю, мне жаль :/
Ответ №5:
Вышеупомянутое решение не работает для меня. В моем случае пользовательский контроллер представления, вложенный в сложный UINavigationController, не вызывается viewWillAppear и viewDidAppear. Используйте ниже в пользовательском контроллере представления:
beginAppearanceTransition(true, animated: animated) // Tells a child controller its appearance is about to change. Do not invoke viewWillAppear(_:), viewWillDisappear(_:), viewDidAppear(_:), or viewDidDisappear(_:) directly.
endAppearanceTransition() // Tells a child controller its appearance has changed.
Ответ №6:
Моя проблема была похожа только на это.
CustomTabBarController -> CustomUINavigationController -> RootViewController
viewWillAppear из CustomUINavigationController и RootViewController не вызываются, если вы не переключились на другую вкладку и не вернулись.
Решением является вызов super.viewWillAppear(анимированный: true)
override func viewWillAppear(_ animated: Bool) {
**super.viewWillAppear(true)**
}
Я боролся больше дня за эту небольшую ошибку.