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

IOS, как программно определить, когда вызывается контроллер верхнего уровня?

Предположим, что у меня есть стек контроллера контроллера с двумя контроллерами представления: VC2 находится сверху, а VC1 находится внизу. Есть ли код, который я могу включить в VC1, который обнаружит, что VC2 только что выскочил из стека?

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

РЕДАКТИРОВАТЬ: мне кажется, что я не совсем понял свой первоначальный вопрос. Здесь то, что я пытаюсь сделать: определить, когда отображается VC1 из-за того, что VC2 выскользнул из верхней части стека. Здесь то, что я НЕ пытаюсь сделать: определить, когда VC1 отображается из-за того, что его вставляют в верхнюю часть стека. Мне нужен способ, который обнаружит первое действие, но НЕ второе действие.

Примечание. Я не особо забочусь о VC2, это может быть любое количество других VC, которые выходят из стека, что меня волнует, когда VC1 снова становится вершиной стека из-за того, что какой-то другой VC начинается выскочил сверху.

4b9b3361

Ответ 1

В iOS 5 были введены два новых метода обработки именно такого типа ситуаций. Вы ищете -[UIViewController isMovingToParentViewController]. Из docs:

isMovingToParentViewController

Возвращает значение Boolean, которое указывает что контроллер представления находится в процессе добавления родителя.

- (BOOL)isMovingToParentViewController

Возвращаемое значение
ДА, если контроллер вида появляется, потому что он был добавлен как дочерний элемент контейнера, иначе NO.

Обсуждение
Этот метод возвращает YES только при вызове изнутри следующие методы:

-viewWillAppear:
-viewDidAppear:

В вашем случае вы можете реализовать -viewWillAppear: следующим образом:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (self.isMovingToParentViewController == NO)
    {
        // we're already on the navigation stack
        // another controller must have been popped off
    }
}

РЕДАКТИРОВАТЬ: Там тонкая смысловая разница, чтобы рассмотреть здесь - вас интересует тот факт, что VC2, в частности, выскочил из стека, или вы хотите получать уведомления каждый раз, когда VC1 отображается как результат какого-либо контроллера? В первом случае делегирование является лучшим решением. Прямая слабая ссылка на VC1 также может работать, если вы никогда не намереваетесь повторно использовать VC2.

EDIT 2: Я сделал пример более явным, инвертируя логику и не возвращаясь раньше.

Ответ 2

isMovingTo/FromParentViewController не будет работать для нажатия и ввода в стек навигационного контроллера.

Здесь надежный способ сделать это (без использования делегата), но это, вероятно, только iOS 7+.

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];

if ([[self.navigationController viewControllers] containsObject:fromViewController])
{
    //we're being pushed onto the nav controller stack.  Make sure to fetch data.
} else {
    //Something is being popped and we are being revealed
}

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

Ответ 3

Один из способов, по которым вы могли бы подойти, - объявить делегатский протокол для VC2 примерно так:

в VC1.h

@interface VC1 : UIViewController <VC2Delegate> {
...
}

в VC1.m

-(void)showVC2 {
    VC2 *vc2 = [[VC2 alloc] init];
    vc2.delegate = self;
    [self.navigationController pushViewController:vc2 animated:YES];
}

-(void)VC2DidPop {
    // Do whatever in response to VC2 being popped off the nav controller
}

в VC2.h

@protocol VC2Delegate <NSObject>
-(void)VC2DidPop;
@end

@interface VC2 : UIViewController {

    id<VC2Delegate> delegate;
}

@property (nonatomic, assign) id delegate;

...

@end

VC2.m

-(void)viewDidUnload {
    [super viewDidUnload];
    [self.delegate VC2DidPop];
}

Здесь есть хорошая статья об основах протоколов и делегатов здесь.

Ответ 4

Вы также можете обнаружить в контроллере представления, который вызывается

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if ([self isMovingFromParentViewController]) {
        ....
    }
}

Ответ 5

Это сработало для меня

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];
if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController)
{
  //Something is being popped and we are being revealed 
}

Ответ 6

Что вы конкретно пытаетесь сделать?

Если вы пытаетесь обнаружить, что VC1 будет показан, этот ответ должен вам помочь. Используйте UINavigationControllerDelegate.

Если вы пытаетесь обнаружить, что VC2 будет скрыт, я просто использую viewWillDisappear: VC2.

Ответ 7

Вы можете добавить наблюдателя для NSNotification специально JUST для вашего VC2.

// pasing the "VC2" here will tell the notification to only listen for notification from
// VC2 rather than every single other objects
[[NSNotitificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) object:VC2];

Теперь в вашем представлении VC2 исчезнет, ​​вы можете отправить уведомление:

-(void)viewWillDisappear
{
    [[NSNotificationCenter defaultCenter] postNotificationNamed:@"notif_dismissingVC2" object:nil];
}

Ответ 8

Да, в VC1 вы можете проверить, всплывает ли VC2. В UINavigationController существует один метод viewControllers, который возвращает массив нажатых контроллеров, которые находятся в стеке (т.е. Которые были нажаты).

Итак, вы повторяете цикл путем сравнения класса. Если VC2, будет иметь совпадение, в противном случае нет.

Ответ 9

swift 3

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if self.isMovingToParentViewController {
            print("View is moving to ParentViewControll")
        }
}

Ответ 10

У меня такая же ситуация, но с небольшим конкретным вариантом использования. В моем случае мы хотели определить, появляется ли VC1/отображается, когда пользователь нажимает кнопку VC2 назад, где VC2 нажимается на navigationController через VC1.

Итак, я использовал help ответ snarshad для настройки по моей потребности. Вот код в VC1 viewDidAppear в swift 3.

// VC1: ParentViewController
// VC2: ChildViewController

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        if let transitionCoordinator = navigationController?.transitionCoordinator,
            let fromVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.from),
            let toVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.to),
            fromVC is ChildViewController,
            toVC is ParentViewController {

            print("Back button pressed on ChildViewController, and as a result ParentViewController appeared")
        }
    }