iOS6中的UIPageViewController

20
在iOS6中,在方法viewControllerAfterViewControllerviewControllerBeforeViewController中,如果我返回nil(以阻止当我处于第一页或最后一页时的页面导航),应用程序会崩溃并显示此异常:

'The number of view controllers provided (0) doesn't match the number required (1) for the requested transition'

在iOS5中一切正常。

жңүи¶Јзҡ„жҳҜпјҢиҝҷдёӘйЎөйқўдёҠзҡ„и§ЈеҶіж–№жЎҲйғҪжІЎжңүж¶үеҸҠеҲ°UIPageViewControllerзҡ„doubleSidedеұһжҖ§гҖӮиҝҷе°ұжҳҜжҲ‘зҡ„й—®йўҳжүҖеңЁ...жҲ–иҖ…иҜҙе…¶дёӯд№ӢдёҖгҖӮ - livingtech
5个回答

28
我遇到了同样的问题。我发现原因是在UIPageViewController的UIPanGestureRecognizer上替换了委托,这实际上是不允许的。手势识别器在调用一个名为 _gestureRecognizerShouldBegin:(注意下划线)的未记录方法时,UIPageViewController实现了这个方法,并显然依赖它正常工作(即不崩溃)。最终,我在使用UIPageViewController的类中实现了respondsToSelector:和forwardingTargetForSelector:,将未记录的委托方法传递给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的使用,以便我不需要更改手势识别器代理。


1
+1. 我最终决定不替换panGestureRecognizer.delegate作为我的viewController。 - inamiy
所以...我不明白。这个解决方案会使你的应用被拒绝吗?也许最好采用@puneeth的建议? - n.evermind
这会被苹果拒绝吗? - Bagusflyer
使用两个UIViewController,动态加载页面并修复您的问题,节省了我的时间。非常感谢,相信苹果不会拒绝我们的应用程序 :) - iTux

12

啊,我在想为什么没有人指出这个bug,我花了近两个晚上才找到解决方案。

旧代码(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;
    }
}

解决方案(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];
}

这对我来说似乎是最好的解决方案,只不过我使用了比0.0更大的速度阈值,因为该错误似乎与非常快的平移轻扫有关。 - jsbox

7
这已经得到了深入讨论,但我有一点要补充。考虑一下将手势识别器的委托设置为self的原因。在我的情况下,是因为在某些情况下,我想通过委托的gestureRecognizerShouldBegin:方法阻止手势识别器的识别。
但在iOS 6中,出现了这个问题,有一种全新的方法可以实现这一点,即在UIView上实现gestureRecognizerShouldBegin:方法。(这是iOS 6中的一个新的UIView实例方法。)
因此,我能够像以前一样完成我的任务,而不用修改手势识别器的委托。

这是最好的答案。然而,文档本身省略了一个在UIView.h头文件中提到的细节:“当识别器尝试从UIGestureRecognizerStatePossible状态转换出来时,如果由于手势识别而取消了对此视图进行触摸测试,则会调用_called方法”。这意味着您必须对触摸测试命中的视图进行子类化,否则您可能不需要;在我的情况下,我不得不子类化UISlider才能实现这个方法。 - Charles A.

1

我遇到了一个问题,使用UIPageViewController在iOS6上崩溃,并显示相同的错误信息(“提供的视图控制器数量(0)与所需的数量(1)不匹配,无法进行请求的转换”)。

以上解决方案都没有对我起作用,但最终我发现将以下行从viewDidLoad移动到viewDidAppear中可以解决这个问题。

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

1
这对我来说并没有消除崩溃的问题。 - Dan Reese

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

这意味着你可以无限翻页,但我没有其他选择... 更好的解决方案总是受欢迎的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接