如何解决"无法确定滚动的导航方向"错误

Mat*_*uif 27 iphone debugging ios uipageviewcontroller ios7

我最常见的错误是"无法确定滚动的导航方向",我有任何想法可以解决它吗?

这是最后一个Exception Backtrace:

 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)
Run Code Online (Sandbox Code Playgroud)

更新: 我终于设法重现模拟器上的错误,当我触摸视图时,同时,UIPageViewController滚动动画以编程方式启动.基本上,如果以编程方式设置ViewsControllers,并将动画设置为yes并滚动动画.如果您在滚动动画开始之前触摸屏幕的任何部分,则会出现以下崩溃***断言失败 - [_ UIQueuingScrollView _didScrollWithAnimation:force:],/ SourceCache/UIKit/UIKit-2372/_UIQueuingScrollView.m:778作为描述在这里.

我还下载了Apple的PhotoScroller示例应用程序,并通过程序化页面更改对其进行了编辑,它们也有相同的错误.

我的解决方案是,如果用户当前正在触摸屏幕,则不会触发页面更改,您也可以将动画更改为卷曲或删除动画.

Jam*_*ang 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的代码中以编程方式转换页面视图,仅在页面控制器尚未转换时才继续.

if (!self.isTransitioning) {
    [self.pageController setViewControllers:@[toViewController]
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:YES
                                 completion:nil];
}
Run Code Online (Sandbox Code Playgroud)


Mat*_*uif 4

正如我在问题更新中提到的,UIPageViewController 似乎在更改页面动画结束时在以下条件下崩溃:

  • 以编程方式更改页面
  • 页面变化是动画的
  • TransitionStyle 等于 UIPageViewControllerTransitionStyleScroll
  • 页面更改开始时用户正在触摸屏幕

只需添加一个编程页面更改,我就能够在 Apple 的 PhotoScroller 示例应用程序中重现该错误。所以这个错误似乎是苹果的错。

由于我无法解决该错误,因此我删除了触发该错误的条件之一(等待更好的解决方案)。我不同意使用卷曲过渡(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];
}
Run Code Online (Sandbox Code Playgroud)

currentViewController.view 是 UIView 的子类,在标头中实现以下属性

@property (nonatomic, assign) BOOL isBeingTouch;
Run Code Online (Sandbox Code Playgroud)

以及 main 中的以下方法

- (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;
}
Run Code Online (Sandbox Code Playgroud)

我只有按钮作为子视图,所以它适用于大多数情况。但是,可能有更完整的解决方案