20

在 iOS6 中的 viewControllerAfterViewController 和 viewControllerBeforeViewController 方法如果我返回 nil(当我在第一页或最后一页时阻止页面导航),应用程序崩溃并出现以下异常:

'提供的视图控制器数量 (0) 与请求的转换所需的数量 (1) 不匹配'

在 iOS5 中一切正常。

4

5 回答 5

29

我遇到过同样的问题。我发现原因是替换 UIPageViewController 的 UIPanGestureRecognizer 上的委托,这确实是不行的。平移手势识别器正在调用一个未记录的方法 _gestureRecognizerShouldBegin:(注意前导下划线),UIPageViewController 实现并显然依赖于它才能正常工作(阅读:不崩溃)。我最终在我的类中实现了 respondsToSelector: 和 forwardingTargetForSelector: ,它使用 UIPageViewController 将未记录的委托方法传递给 UIPageViewController 而不具体命名它(并且几乎肯定会为我赢得应用商店审查拒绝)。

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

我的长期解决方案是重新使用 UIPageViewController,这样我就不需要替换手势识别器代表了。

于 2012-09-24T22:10:06.670 回答
12

啊,想知道为什么没有人指出这个错误,我花了将近 2 个晚上才找到解决方案。

旧代码(iOS 5.1):当在第一页和最后一页返回 nil 时,您会遇到应用程序崩溃。它在 iOS 5.1 中运行良好,但在 iOS 6 中不会。

- (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) : 将手势效果添加到超级视图后,只需调用名为 -(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 的委托。我所做的很简单,计算用户翻动第一页和最后一页的速度(我的意思是使用手势识别器),我拒绝滑动。您只需粘贴以下代码,您就完成了!.

- (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];
}
于 2012-10-08T06:47:56.483 回答
7

这已经得到了很好的讨论,但我还有一件事要补充。考虑一下为什么要将手势识别器的委托设置为 self。就我而言,这是因为在某些情况下,我想阻止手势识别器识别,代表的gestureRecognizerShouldBegin:.

gestureRecognizerShouldBegin:但是在出现这个问题的 iOS 6 中,通过在 UIView 上实现,有一种全新的方法可以做到这一点。(这是 iOS 6 中新增的 UIView 实例方法。)

因此,我能够完全完成我之前完成的工作,而无需更改手势识别器的委托。

于 2012-10-17T16:39:44.390 回答
1

我遇到了 UIPageViewController 与 iOS6 崩溃并出现相同错误的问题(“提供的视图控制器的数量 (0) 与请求的转换所需的数量 (1) 不匹配”)。

上述解决方案都不适合我,但我最终发现将以下行从移动viewDidLoadviewDidAppear修复它。

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
于 2012-11-19T17:18:49.720 回答
-1

这里完全一样的问题。

我所做的是一个修补程序,它只是返回 before/afterViewController 的克隆而不是 nil,即

// viewController = before/afterViewController
NSUInteger index = [self indexOfViewController:viewController];

// NOTE: return nil crashes in iOS6
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];

这意味着您可以永远翻页,但我别无选择......总是欢迎更好的解决方案。

于 2012-09-24T16:39:52.570 回答