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

При использовании UINavigationController методы viewWillAppear или viewDidAppear моего контроллера не вызываются

Вот высота.

  • У меня есть подкласс 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.

4b9b3361

Ответ 1

ПРИМЕЧАНИЕ: это было написано в 2013 году. Изменения в способе обработки имен iOS в настоящее время могут сделать это решение бесполезным и/или опасным. Поэтому используйте на свой страх и риск.

Оригинальный ответ При вложенности пользовательского UIViewController под UINavigationController методы viewWillAppear и viewDidAppear настраиваемого диспетчера viewController могут не вызываться в зависимости от сложности иерархии вашего контроллера представления (подумайте о модельных представлениях, контроллере навигации в контроллере просмотра вкладок...). Итак, если вы окажетесь в этой ситуации, что вы можете сделать, чтобы эти два метода были вызваны?

Ответ...

Используйте методы 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 не называются, вы теперь знаете, что делать...

Ответ 2

Одна из причин, по которой это произойдет, - это переопределить viewDidAppear: в подклассе UINavigationController и не вызывать [super viewDidAppear:animated];...

Ответ 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;
}