Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In ios6, setting your pageViewController's gestureRecognizers delegate to a viewController causes a crash

This has only started happening with ios6, but if you start a new project using the page view controller template. Then in

PCRootViewControlle::viewDidLoad()

add the lines to the bottom of the method.

for (UIGestureRecognizer *gR in self.pageViewController.gestureRecognizers)
{
    gR.delegate = self;
}

You'll need to assign the viewController so it conforms to the UIGestureRecognizerDelegate and implement the method

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch (UITouch *)touch
{
    return YES;
}

Now if you run the app and try to turn the page beyond the bounds, i.e. go to January and try to turn back so

  • (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController

returns nil.

The app will then crash.

This did not happen with ios5. I need to assign the gestureRecognizer delegate to my viewController because I do not always want the pageViewController to handle the touch events.

Has any else experienced this or point out If I am doing something wrong?

Many Thanks Stewart.

like image 918
noRema Avatar asked Sep 24 '12 08:09

noRema


1 Answers

Finally found a solution to my problem which has caused me grief so hopefully this can help someone else.

The issue is if you set the pageViewControllers delegate to your viewController

for (UIGestureRecognizer *gR in self.pageController.view.gestureRecognizers) 
{
    if ([gR isKindOfClass:[UITapGestureRecognizer class]])
    {
        gR.enabled = NO;
    }
    else if ([gR isKindOfClass:[UIPanGestureRecognizer class]])
    {
        gR.delegate = self;
    }
}

then returning nil from

pageViewController:viewControllerAfterViewController:

will crash!! only in iOS6!!

My issue was that I needed to set the delegate of the gestureRecognisers because I needed to intercept the panGesture in some situations, i.e not allowing the user to turn a page wilst touching certain parts of it due to some buttons there.

The solution is to put the logic from

pageViewController:viewControllerAfterViewController: 

into

gestureRecognizer:shouldReceiveTouch:

because as long as we return NO from that then it wont go on to call

pageViewController:viewControllerAfterViewController:

and so no need to return nil and get a crash.

However, this didn't work on the first and last page in the sequence. For example on the first page, you want to allow the page to turn forward but not back. So I thought about looking at the GestureRecogniser passed in, casting it to a PanGesture, and then checking the velocity on this, if the velocity signifies turning back ( > 0.0f ) then just return NO. This sounded good but the velocity was always zero.

I then found a very helpful little function on the GestureRecognizer delegate called:

gestureRecognizerShouldBegin:gestureRecognizer

this function is called after

gestureRecognizer:shouldReceiveTouch:

but this time the velocity from the gesture is as I expected, so I can check the velocity and only return YES for the first page if it is > 0.0f

like image 85
noRema Avatar answered Sep 20 '22 06:09

noRema