it-roy-ru.com

UIViewController viewWillAppear не вызывается при добавлении в качестве subView

У меня есть UIViewController, который я загружаю из другого контроллера представления и затем добавляю его представление в UIScrollView.

self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"];
self.statisticsController.match = self.match;

[self.scrollView addSubview:self.statisticsController.view];

Я установил контрольные точки в контроллере представления статистики и вызывается viewDidLoad, а viewWillAppear нет.

Это потому что я не толкаю это на иерархию или что-то?

20
Fogmeister

Вы должны добавить statisticsController в качестве дочернего контроллера представления контроллера, в представление которого вы добавляете его.

self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"];
self.statisticsController.match = self.match;

[self.scrollView addSubview:self.statisticsController.view];
[self addChildViewController:self.statisticsController];
[self.statisticsController didMoveToParentViewController:self];

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

43
rdelmar

Я снова столкнулся с проблемой -viewWillAppear:. Погуглив, я пришел сюда. Я провел несколько тестов и выяснил, что порядок вызова -addSubview и -addChildViewController: важен.

Case 1. вызовет -viewWillAppear: контроллера, но Case 2, it WON'T вызовет -viewWillAppear:.

Случай 1:

  controller?.willMoveToParentViewController(self)

  // Call addSubview first
  self.scrollView.addSubview(controller!.view)
  self.addChildViewController(controller!)

  controller!.didMoveToParentViewController(self)

Случай 2:

  controller?.willMoveToParentViewController(self)

  // Call adChildViewController first      
  self.addChildViewController(controller!)      
  self.scrollView.addSubview(controller!.view)

  controller!.didMoveToParentViewController(self)
36
AechoLiu

По умолчанию обратные вызовы внешнего вида автоматически перенаправляются дочерним элементам . Это определяется свойством shouldAutomaticsForwardAppearanceMethods. Проверьте значение этого свойства, если оно NO и если ваш дочерний viewController должен отображаться прямо при появлении контейнера, вы должны уведомить дочерний процесс следующими методами в реализации жизненного цикла контроллера контейнера:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    for (UIViewController *child in self.childViewControllers) {
        [child beginAppearanceTransition:YES animated:animated];
    }
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.child endAppearanceTransition];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    for (UIViewController *child in self.childViewControllers) {
        [child beginAppearanceTransition:NO animated:animated];
    }
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [self.child endAppearanceTransition];
}

Настройка внешнего вида и поведения обратного вызова вращения

Исправлена ​​моя проблема! Надеюсь, это будет полезно. 

16
Alexander Larionov

Как упоминалось в другом ответе, родительский контроллер представления может не вызывать viewWillAppear и т.д., Если для shouldAutomaticallyForwardAppearanceMethods установлено значение false. UINavigationController и UITabBarController, как известно, делают это. В этом случае вам нужно вызвать beginAppearanceTransition(_ isAppearing: Bool, animated: Bool) на дочернем контроллере представления с isAppearing, установленным на true, когда представление появляется, и наоборот.

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

Не забудьте вызвать endAppearanceTransition на вашем дочернем контроллере представления, когда ваш пользовательский переход завершится, иначе viewDidAppear и viewDidDisappear не будут вызваны.

4
bompf

Для Apple ( https://developer.Apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html ) правильный порядок вызовов API для добавления дочернего контроллера представления:

[self addChildViewController:childVC];
[self.view addSubview:childVC.view];
[childVC didMoveToParentViewController:self];

Но у меня все еще была проблема, когда viewWillAppear у ребенка VC не вызывался время от времени. Моя проблема заключалась в том, что имелось состояние гонки, которое могло привести к выполнению кода выше до вызова viewDidAppear в контроллере представления контейнера. Решение того, что viewDidAppear уже был вызван (или отложено добавление дочернего элемента VC до его появления), решило это для меня.

2
gumbypp

Предыдущие ответы верны, но в случае, если это кому-то поможет - если вы переопределите loadView в дочернем контроллере представления, тогда не будет вызван ни один из других методов UIViewController.

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

1
Liron

В моем случае я обнаружил, что неправильно переписал метод viewWillAppear: в моем базовом классе UINavigationController:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    // other stuff
}

Обратите внимание, что вместо вызова super.viewWillAppear(animated) я написал super.viewWillDisappear(animated).

Это привело к тому, что все UIViewController, которые были внутри этого UINavigationController, не вызывали метод viewWillAppear:.

Надеюсь, что это поможет кому-то по аналогичной проблеме.

0
Shyngys Kassymov