一、问题描述
使用iPhone 真机测试过程中,当从ViewController A push到ViewController B时程序失去响应,按主屏按钮将程序切换到后台,再返回前台,程序恢复正常,且显示ViewController B。该问题不是确定出现,但是出现的比较频繁。
二、问题分析及解决方案
1. 问题分析
经网上查找类似问题解决方案和对代码的分析发现,此问题的发生与3个方面有比较大的关系:
1.)push动画是否开启,只有当开启动画时,问题才有一定几率发生
2. )当前ViewController 是否是Root ViewController
3. )是否支持interactivePopGestureRecognizer(既右滑pop)
仔细分析如下:
在当前ViewController是Root ViewController时,由于已经是NavigationController栈中的最后一个ViewController是不应该执行pop操作的,但由于interactivePopGestureRecognizer是对整个栈中所有的ViewController开启的,因此如果不做处理,默认Root ViewController也支持interactivePopGestureRecognizer,当Root ViewController interactivePopGestureRecognizer手势时会试图去pop Root ViewController,一旦这种识别发生了,再通过点击等方式push ViewController(带动画)时,程序就会卡死在被Push ViewController的viewWillAppear方法执行之后。
这种情况只有在push操作开启动画时才会发生,至于为什么,不太清楚。可能之前Root ViewController 识别interactivePopGestureRecognizer后,试图启动pop动画但是失败,当再启动push动画时就会出问题。
2. 解决方法
方法一:
1)取消push动画
一般不太建议此方法,因为动画没了影响用户体验;
2) 在Root ViewController上使interactivePopGestureRecognizer手势失效
我采用的是如下方法:
第一步:在Root ViewController的viewDidLoad中设置
self.navigationController.interactivePopGestureRecognizer.delegate = self;
第二步:添加如下代理方法,使interactivePopGestureRecognizer手势失效
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([self.navigationControllerrespondsToSelector:@selector(interactivePopGestureRecognizer)]
&& gestureRecognizer ==self.navigationController.interactivePopGestureRecognizer
&& self.navigationController.visibleViewController == [self.navigationController.viewControllers objectAtIndex:0]) {
NSLog(@"Gesture blocked===手势锁定");
return NO;
}
NSLog(@"Gesture begin===手势开启");
return YES;
}
方法二:
在RootViewController的viewDidAppear方法中设置
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
在RootViewController viewDidDisappear方法或被push的ViewController的viewDidAppear方法中设置
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
但是这种方法处理可能会对其他页面的手势有影响可能存在问题。因为有的时候会出现viewDidAppear不执行就可能会出bug,实测出现过不执行的情况。
其他方法:
网上有一种继承UINavigationController类并重写push和pop方法,在其中设置interactivePopGestureRecognizer.enabled属性,但我实测发现直接会使App挂起,此处不多做介绍了
三、其他发现
1. 测试发现:ViewController的viewDidAppear方法不一定会执行,有时候会从viewWillAppear方法直接跳到viewWillDisappear方法,可能是场景切换太快造成的。
2. 测试发现:UINavigationControllerDelegate的didShowViewController方法不一定执行,不执行的原因不详。
四、其他
手势中的设定优先顺序,避免冲突处理
[A requireGestureRecognizerToFail:B]函数,它可以指定当A手势发生时,即便A已经滿足条件了,也不会立刻触发,会等到指定的手势B确定失败之后才触发。