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.
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];
}
As I mention in the question update, UIPageViewController seems to crash in the following conditions at the end of the change page animation:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With