При использовании UINavigationController методы viewWillAppear или viewDidAppear моего контроллера не вызываются - PullRequest
13 голосов
/ 06 октября 2011

Вот шаг.

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

Ответы [ 5 ]

21 голосов
/ 06 октября 2011

ПРИМЕЧАНИЕ: это было написано в 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 не будут вызваны, вы теперь знаете, что делать ...

8 голосов
/ 05 февраля 2015

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

3 голосов
/ 03 октября 2015

Сейчас 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 :(
}

Просто поделитесь этим выводом здесь на случай, если люди столкнутся ста же проблема.

0 голосов
/ 30 мая 2019

Приведенное выше решение не работает для меня.В моем случае пользовательский контроллер представления, вложенный в сложный контроллер 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.
0 голосов
/ 06 октября 2011

это должно быть сделано следующим образом:

См. (* 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...