Reputation: 1288
In iOS6 in the methods viewControllerAfterViewController and viewControllerBeforeViewController if I return nil (for block the page navigation when I am in the first or last page) the app crash with this exception:
'The number of view controllers provided (0) doesn't match the number required (1) for the requested transition'
In iOS5 all works good.
Upvotes: 20
Views: 9043
Reputation: 5128
Ah,was wondering why no one has pointed out this bug,which i took almost 2 nights to find out the solution.
OLD CODE(iOS 5.1) : when returning nil on the first and last page you will experience the app crash.It works fine in iOS 5.1,but in iOS 6 it wont.
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerBeforeViewController:
(UIViewController *)viewController
{
for (UIGestureRecognizer *recognizer in pageController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
NSUInteger index = [self indexOfViewController:
(MainViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
for (UIGestureRecognizer *recognizer in pageController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
NSUInteger index = [self indexOfViewController:
(MainViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
}
SOLUTION(iOS 6) : After adding the gesture effect to the superview,just call the delegate called -(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer. What i did is quiet simple, computing the speed of the user flipping the first page and last page (i mean using the gesture recognizer) , i denied the swiping.All you need to do is just paste the following code,and you are DONE!.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if (pageNum==0) {
if ([(UIPanGestureRecognizer*)gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
[(UIPanGestureRecognizer*)gestureRecognizer velocityInView:gestureRecognizer.view].x > 0.0f) {
//NSLog(@"Swiping to left on 1st page is denied");
return NO;
}
if ([(UITapGestureRecognizer*)gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
[(UITapGestureRecognizer*)gestureRecognizer locationInView:gestureRecognizer.view].x < self.view.frame.size.width/2) {
//NSLog(@"tapping to left on 1st page is denied");
return NO;
}
}
else if(pageNum ==totalNoOfFiles-1)
{
if ([(UIPanGestureRecognizer*)gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
[(UIPanGestureRecognizer*)gestureRecognizer velocityInView:gestureRecognizer.view].x < 0.0f) {
//NSLog(@"Swiping to right on 1st page is denied");
return NO;
}
if ([(UITapGestureRecognizer*)gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
[(UITapGestureRecognizer*)gestureRecognizer locationInView:gestureRecognizer.view].x > self.view.frame.size.width/2) {
//NSLog(@"Tapping to right on 1st page is denied");
return NO;
}
}
return YES;
}
- (UIViewController *)pageViewController:(UIPageViewController*) pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
int index = [self indexOfViewController:(ChildViewController *)viewController];
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
int index = [self indexOfViewController:(ChildViewController *)viewController];
index++;
return [self viewControllerAtIndex:index];
}
Upvotes: 12
Reputation: 1058
I had the issue with UIPageViewController crashing with iOS6 with the same error ('The number of view controllers provided (0) doesn't match the number required (1) for the requested transition').
None of the above solutions worked for me but I eventually found that moving the following line from viewDidLoad
to viewDidAppear
fixed it.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
Upvotes: 1
Reputation: 535556
This has been well discussed but I have one thing to add. Consider why you were setting the delegate of the gesture recognizers to self. In my case, it was because in some cases I wanted to prevent the gesture recognizers from recognizing, with the delegate's gestureRecognizerShouldBegin:
.
But in iOS 6, where this issue arises, there is a whole new way of doing exactly that, by implementing gestureRecognizerShouldBegin:
on a UIView. (This is a new UIView instance method in iOS 6.)
Thus I was able to accomplish exactly what I was accomplishing before, without altering the gesture recognizers' delegate.
Upvotes: 7
Reputation: 323
I had the same issue. I found that the cause was replacing the delegate on the UIPanGestureRecognizer of the UIPageViewController, a no-no really. The pan gesture recognizer was calling an undocumented method _gestureRecognizerShouldBegin: (note the leading underscore) that UIPageViewController implements and apparently relies upon to work properly (read: not-crash). I ended up implementing respondsToSelector: and forwardingTargetForSelector: in my class that uses the UIPageViewController to pass the undocumented delegate method on to the UIPageViewController without specifically naming it (and almost certainly earning me an app store review rejection).
-(BOOL)respondsToSelector:(SEL)aSelector {
if ([super respondsToSelector:aSelector])
return YES;
else if ([self.pageViewController respondsToSelector:aSelector])
return YES;
else
return NO;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([super respondsToSelector:aSelector]) {
return nil;
} else if ([self.pageViewController respondsToSelector:aSelector]) {
return self.pageViewController;
}
return nil;
}
My longer term solution will be to rework the use of UIPageViewController such that I don't need to displace the gesture recognizer delegates.
Upvotes: 28
Reputation: 2996
Totally same issue here.
What I did was a hotfix which just to returns clone of before/afterViewController instead of nil, i.e.
// viewController = before/afterViewController
NSUInteger index = [self indexOfViewController:viewController];
// NOTE: return nil crashes in iOS6
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
This means you can page-curl forever but I had no other choice... Better solution is always welcome.
Upvotes: -1