viewWillDisappear: Определите, выталкивается ли контроллер представления или показывает контроллер подвида
Я изо всех сил пытаюсь найти хорошее решение этой проблемы. В представлении контроллера -viewWillDisappear:
метод, мне нужно найти способ определить, происходит ли это потому, что контроллер представления помещается в стек контроллера навигации, или это происходит потому, что контроллер представления исчезает, потому что он вытолкнут.
На данный момент я устанавливаю такие флаги как isShowingChildViewController
но это становится довольно сложно. Единственный способ, которым я могу обнаружить это в -dealloc
метод.
12 ответов
Вы можете использовать следующее.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSArray *viewControllers = self.navigationController.viewControllers;
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
// View is disappearing because a new view controller was pushed onto the stack
NSLog(@"New view controller was pushed");
} else if ([viewControllers indexOfObject:self] == NSNotFound) {
// View is disappearing because it was popped from the stack
NSLog(@"View controller was popped");
}
}
Это, конечно, возможно, потому что стек контроллера представления UINavigationController (предоставляемый через свойство viewControllers) был обновлен к моменту вызова viewWillDisappear.
Я думаю, что самый простой способ это:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController])
{
NSLog(@"View controller was popped");
}
else
{
NSLog(@"New view controller was pushed");
}
}
Swift:
override func viewWillDisappear(animated: Bool)
{
super.viewWillDisappear(animated)
if isMovingFromParentViewController
{
print("View controller was popped")
}
else
{
print("New view controller was pushed")
}
}
Из документации Apple в UIViewController.h:
"Эти четыре метода могут использоваться в обратных вызовах внешнего вида контроллера представления, чтобы определить, будет ли он представлен, отклонен, добавлен или удален как дочерний контроллер представления. Например, контроллер представления может проверить, исчезает ли он, потому что он был отклонен или выскочил, спросив себя в своем viewWillDisappear: метод, проверив выражение ([self isBeingDismissed] || [self isMovingFromParentViewController])."
- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);
- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);
Так что да, единственный документированный способ сделать это заключается в следующем:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
}
}
Версия Swift 3:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed || self.isMovingFromParentViewController {
}
}
Swift 4
override func viewWillDisappear(_ animated: Bool)
{
super.viewWillDisappear(animated)
if self.isMovingFromParent
{
//View Controller Popped
}
else
{
//New view controller pushed
}
}
Если вы просто хотите узнать, что ваш взгляд всплывает, я просто обнаружил, что self.navigationController
является nil
в viewDidDisappear
, когда он удаляется из стека контроллеров. Так что это простой альтернативный тест.
(Это я обнаружил после того, как попробовал все виды других искажений. Я удивлен, что нет протокола контроллера навигации, чтобы зарегистрировать контроллер представления, чтобы получать уведомления о всплывающих окнах. Вы не можете использовать UINavigationControllerDelegate
потому что это на самом деле действительно работает дисплей.)
В Свифте:
override func viewWillDisappear(animated: Bool) {
if let navigationController = self.navigationController {
if !contains(navigationController.viewControllers as! Array<UIViewController>, self) {
}
}
super.viewWillDisappear(animated)
}
Спасибо @Bryan Henry, все еще работает в Swift 5
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let controllers = navigationController?.children{
if controllers.count > 1, controllers[controllers.count - 2] == self{
// View is disappearing because a new view controller was pushed onto the stack
print("New view controller was pushed")
}
else if controllers.firstIndex(of: self) == nil{
// View is disappearing because it was popped from the stack
print("View controller was popped")
}
}
}
Я нахожу документацию Apple об этом трудной для понимания. Это расширение помогает видеть состояния при каждой навигации.
extension UIViewController {
public func printTransitionStates() {
print("isBeingPresented=\(isBeingPresented)")
print("isBeingDismissed=\(isBeingDismissed)")
print("isMovingToParentViewController=\(isMovingToParentViewController)")
print("isMovingFromParentViewController=\(isMovingFromParentViewController)")
}
}
Segues может быть очень эффективным способом решения этой проблемы в iOS 6+. Если вы дали конкретному seue идентификатор в Интерфейсном Разработчике, вы можете проверить его в prepareForSegue
,
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"LoginSegue"]) {
NSLog(@"Push");
// Do something specific here, or set a BOOL indicating
// a push has occurred that will be checked later
}
}
Это относится к iOS7, не знаю, применимо ли это к любым другим. Из того, что я знаю, в viewDidDisappear
вид уже был выскочил. Что означает, когда вы запрашиваете self.navigationController.viewControllers
вы получите nil
, Так что просто проверьте, если это ноль.
TL; DR
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if (self.navigationController.viewControllers == nil) {
// It has been popped!
NSLog(@"Popped and Gone");
}
}
Этот вопрос довольно старый, но я видел его случайно, поэтому я хочу опубликовать лучшие практики (afaik)
ты можешь просто сделать
if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
// view controller popped
}
Я предполагаю, что вы имеете в виду, что ваше представление перемещается вниз по стеку контроллера навигации путем нажатия нового представления, когда вы говорите, что помещено в стек. Я бы предложил использовать viewDidUnload
способ добавить NSLog
заявление, чтобы написать что-то на консоль, чтобы вы могли видеть, что происходит, вы можете добавить NSLog
в viewWillDissappeer
,
Вот категория для выполнения того же, что и в ответе sbrocket:
Заголовок:
#import <UIKit/UIKit.h>
@interface UIViewController (isBeingPopped)
- (BOOL) isBeingPopped;
@end
Источник:
#import "UIViewController+isBeingPopped.h"
@implementation UIViewController (isBeingPopped)
- (BOOL) isBeingPopped {
NSArray *viewControllers = self.navigationController.viewControllers;
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
return NO;
} else if ([viewControllers indexOfObject:self] == NSNotFound) {
return YES;
}
return NO;
}
@end