假设我有一个带有2个视图控制器的导航控制器堆栈:VC2位于顶部,VC1位于底层。我可以在VC1中包含哪些代码来检测VC2刚刚从堆栈中弹出?
由于我试图从VC1的代码中检测到VC2的弹出,似乎 viewWillAppear 或 viewDidAppear 之类的东西不起作用,因为这些方法每次显示VC1时都会触发,包括第一次按下它时。
编辑:我原来的问题似乎不太清楚。这是我正在尝试做的事情:确定VC1何时显示是由于VC2从堆栈顶部弹出。这是我不想做的事情:确定VC1由于被推到堆栈顶部而显示的时间。我需要某种方法来检测第一个动作但不是第二个动作。
注意:我并不特别关心VC2,它可以是任何数量的其他VC从堆栈弹出,我关心的是当VC1由于其他一些VC开始再次成为堆栈的顶部从顶部弹出。
答案 0 :(得分:63)
iOS 5引入了两种新方法来处理这种情况。您要找的是-[UIViewController isMovingToParentViewController]
。来自docs:
<强> isMovingToParentViewController 强>
返回指示的布尔值 视图控制器正在被添加到父级。
- (BOOL)isMovingToParentViewController
返回值
如果视图控制器出现,则为YES,因为它是作为容器的子项添加的 查看控制器,否则为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显示为任何控制器弹出的结果?在前一种情况下,授权是一种更好的解决方案。如果您从未打算重用VC2,那么对VC1的直接弱引用也可以起作用。
编辑2:我通过反转逻辑并且不提前返回来使示例更加明确。
答案 1 :(得分:15)
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
}
在我的情况下,使用委托意味着拥有视图控制器&#39;行为与拥有导航堆栈的代理更紧密地结合在一起,我想要一个更独立的解决方案。这有效。
答案 2 :(得分:7)
您可以采用的一种方法是为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];
}
关于协议和代理here的基础知识有一篇很好的文章。
答案 3 :(得分:4)
您还可以在正在弹出的视图控制器中检测
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]) {
....
}
}
答案 4 :(得分:1)
这对我有用
UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];
if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController)
{
//Something is being popped and we are being revealed
}
答案 5 :(得分:0)
你有什么特别的尝试?
如果您尝试检测即将显示VC1,this回答应该会对您有所帮助。使用UINavigationControllerDelegate。
如果您尝试检测VC2即将被隐藏,我只会使用VC2的viewWillDisappear:
。
答案 6 :(得分:0)
是的,在 VC1 中,您可以检查是否弹出 VC2 。 UINavigationController有一个方法 viewControllers ,它将返回被推送的控制器的数组,它们在堆栈中(即已被推送)。
所以你通过比较类来迭代循环。如果 VC2 存在,则匹配,否则不匹配。
答案 7 :(得分:0)
swift 3
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if self.isMovingToParentViewController {
print("View is moving to ParentViewControll")
}
}
答案 8 :(得分:0)
我得到了相同的情况,但有一些更具体的用例。就我而言 我们想确定当用户点击VC2的后退按钮时是否出现/显示VC1,其中VC2被推送到VC1上的navigationController上。
所以我使用snarshad's answer的帮助来根据我的需要进行定制。以下是VC1中 swift 3 中viewDidAppear
的代码。
// 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")
}
}
答案 9 :(得分:-1)
您可以为您的VC2添加NSNotification的观察者,特别是JUST。
// 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];
}