Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve "Failed to determine navigation direction for scroll" bug

My most frequent bug has "Failed to determine navigation direction for scroll" for reason, any idea about how I could solve it?

Here is the last 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)

UPDATE : I finally managed to reproduce the bug on the simulator, it's when I'am touching a view and that at the same time, the UIPageViewController scroll animation starts programmatically. Basically, if you setViewsControllers programmatically with animation set to yes and scroll animation. If you're touching any part of the screen before the scroll animation starts there will be the following crash *** Assertion failure in -[_UIQueuingScrollView _didScrollWithAnimation:force:], /SourceCache/UIKit/UIKit-2372/_UIQueuingScrollView.m:778 as described here .

I also downloaded Apple's PhotoScroller sample app and edited it with programmatic page change and they have the same bug.

My solution was not to trigger the page change if the user is currently touching the screen, you can also change the animation to curl or remove the animation.

like image 230
Matthieu Rouif Avatar asked Nov 12 '13 20:11

Matthieu Rouif


2 Answers

Ideally we would want to know whether the underlying UIScrollView is being dragged or decelerating. But Apple doesn't allow public access to the UIScrollView in the page controller, so we can keep track of the page controller's transition state with a BOOL via these two delegates.

- (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;
    }
}

In your code to programmatically transition the page views, only proceed if the page controller isn't already transitioning.

if (!self.isTransitioning) {
    [self.pageController setViewControllers:@[toViewController]
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:YES
                                 completion:nil];
}
like image 64
James Kuang Avatar answered Oct 26 '22 01:10

James Kuang


As I mention in the question update, UIPageViewController seems to crash in the following conditions at the end of the change page animation:

  • Change page programmatically
  • Page change is animated
  • TransitionStyle is equal to UIPageViewControllerTransitionStyleScroll
  • User is touching the screen when the page change starts

I was able to reproduce the bug in Apple's PhotoScroller sample app, just by adding a programmatic page change. So the bug seems to be Apple's fault.

As I wasn't able to solve the bug, I remove one of the condition that trigger the bug (waiting for a better solution). I wasn't ok with using a curl transition (UIPageViewControllerTransitionStyleCurl) or removing the transition animation. Both these solutions work. So, when user is touching the screen I don't trigger the programmatic page change with the following line

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];
}

With currentViewController.view being a subclass of UIView implementing the following property in header

@property (nonatomic, assign) BOOL isBeingTouch;

and the following methods in 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;
}

I just have buttons as subviews, so it works for most of the cases. However, there might a more complete solution

like image 42
Matthieu Rouif Avatar answered Oct 26 '22 02:10

Matthieu Rouif