我最常见的错误是“无法确定滚动的导航方向”,我有什么理由可以解决它吗?
这是最后一个异常回溯:
1. CoreFoundation __exceptionPreprocess + 131
2. libobjc.A.dylib _objc_exception_throw + 39
3. CoreFoundation +[NSException raise:format:] + 1
4. Foundation -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 91
5. UIKit __54-[_UIQueuingScrollView _didScrollWithAnimation:force:]_block_invoke + 221
6. UIKit -[_UIQueuingScrollView _didScrollWithAnimation:force:] + 567
7. UIKit -[_UIQueuingScrollView _scrollViewAnimationEnded:finished:] + 73
8. UIKit -[UIAnimator stopAnimation:] + 471
9. UIKit -[UIAnimator(Static) _advanceAnimationsOfType:withTimestamp:] + 285
10. UIKit -[UIAnimator(Static) _LCDHeartbeatCallback:] + 53
11. QuartzCore CA::Display::DisplayLinkItem::dispatch() + 99
12. QuartzCore CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 345
13. IOMobileFramebuffer IOMobileFramebufferVsyncNotifyFunc + 105
14. IOKit _IODispatchCalloutFromCFMessage + 249
15. CoreFoundation __CFMachPortPerform + 137
16. CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 35
17. CoreFoundation __CFRunLoopDoSource1 + 347
18. CoreFoundation __CFRunLoopRun + 1399
19. CoreFoundation _CFRunLoopRunSpecific + 523
20. CoreFoundation _CFRunLoopRunInMode + 107
21. GraphicsServices _GSEventRunModal + 139
22. UIKit _UIApplicationMain + 1137
23. MyApp main (main.m:13)
更新: 我终于设法重现了模拟器上的错误,当我触摸视图时,同时,UIPageViewController滚动动画以编程方式启动。基本上,如果以编程方式设置ViewControllers,并将动画设置为yes并滚动动画。如果您在滚动动画开始之前触摸屏幕的任何部分,则会出现以下崩溃***断言失败 - [_ UIQueuingScrollView _didScrollWithAnimation:force:],/ SourceCache / UIKit / UIKit-2372 / _UIQueuingScrollView.m:778正如here所述。
我还下载了Apple的PhotoScroller示例应用程序,并通过程序化页面更改进行了编辑,他们也遇到了同样的错误。
我的解决方案是,如果用户当前正在触摸屏幕,则不会触发页面更改,您也可以将动画更改为卷曲或删除动画。
答案 0 :(得分:8)
理想情况下,我们想知道基础UIScrollView
是否被拖拽或减速。但Apple并不允许公共访问页面控制器中的UIScrollView
,因此我们可以通过这两个代表跟踪BOOL的页面控制器的转换状态。
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
self.transitioning = YES;
}
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
if (finished) {
self.transitioning = NO;
}
}
在您的代码中以编程方式转换页面视图,只有在页面控制器尚未转换时才会继续。
if (!self.isTransitioning) {
[self.pageController setViewControllers:@[toViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
答案 1 :(得分:4)
正如我在问题更新中提到的,UIPageViewController在更改页面动画结束时似乎在以下条件下崩溃:
我能够通过添加程序化页面更改来重现Apple的PhotoScroller示例应用程序中的错误。所以这个错误似乎是Apple的错。
由于我无法解决错误,我删除了触发错误的一个条件(等待更好的解决方案)。我不习惯使用卷曲过渡(UIPageViewControllerTransitionStyleCurl)或删除过渡动画。这些解决方案都有效。因此,当用户触摸屏幕时,我不会使用以下行触发程序化页面更改
UIViewController* currentViewController = [self.viewControllers objectAtIndex:0];
if(currentViewController.view.isBeingTouch){
ContentViewController *nextViewController = [[ContentViewController alloc] init];
NSArray *viewControllers =;
[self setViewControllers: @[loadingController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
}
currentViewController.view是UIView的子类,在头文件
中实现以下属性@property (nonatomic, assign) BOOL isBeingTouch;
以及主要
中的以下方法- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
_isBeingTouch = YES;
[super touchesBegan:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
_isBeingTouch = NO;
[super touchesCancelled:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
_isBeingTouch = NO;
[super touchesEnded:touches withEvent:event];
}
-(BOOL)isBeingTouch{
for (UIView * view in self.subviews){
if([view isKindOfClass:[UIButton class]]) {
UIButton * b = (UIButton *) view;
if(b.isHighlighted)
return YES;
}
}
return _isBeingTouch;
}
我只是将按钮作为子视图,因此适用于大多数情况。但是,可能有更完整的解决方案
答案 2 :(得分:0)
一个非常hacky的解决方案,但这可以防止崩溃。
第1步:收集完整的bug
我使用了Firebase Crashlytics,可让我查明问题所在。
就我而言:
Fatal Exception: NSInternalInconsistencyException
Failed to determine navigation direction for scroll
触发UIScrollview内部崩溃的行是
scrollView.setContentOffset(CGPoint(x: screenWidth, y: 0), animated: false)
当我在页面之间执行快速滚动时(当到达每一页时,我正在改变滚动行为)。
第2步:寻找替代者
由于该函数不会抛出异常,因此我不得不为我的逻辑找到一个替代品:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//print("contentOffset = \(scrollView.contentOffset.x)")
if !self.isLeftScrollEnabled {
disableLeftScroll(scrollView)
}
//...
}
func disableLeftScroll(_ scrollView: UIScrollView) {
let screenWidth = UIScreen.main.bounds.width
if scrollView.contentOffset.x < screenWidth {
// ERROR
scrollView.setContentOffset(CGPoint(x: screenWidth, y: 0), animated: false)
}
}
我只是将setContentOffset(_ :)调用替换为以下内容(在我的情况下效果很好):
scrollView.isScrollEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
scrollView.isScrollEnabled = true
}