Подтвердить что ты не робот

UIPageViewController в iOS6

В iOS6 в методах viewControllerAfterViewController и viewControllerBeforeViewController, если я возвращаю nil (для блокирования навигации по страницам, когда я на первой или последней странице), сбой приложения с этим исключение:

'Число доступных контроллеров представления (0) не соответствует требуемому числу (1) для запрошенного перехода

В iOS5 все работает хорошо.

4b9b3361

Ответ 1

У меня была такая же проблема. Я обнаружил, что причина заключалась в замене делегата на UIPanGestureRecognizer для UIPageViewController, и нет-нет. Признак распознавателя жеста вызывал недокументированный метод _gestureRecognizerShouldBegin: (обратите внимание на верхний знак подчеркивания), который реализует UIPageViewController и, по-видимому, полагается на правильную работу (read: not-crash). Я завершил реализацию responsesToSelector: и 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 таким образом, что мне не нужно будет вытеснять делегатов распознавателя жестов.

Ответ 2

А, было интересно, почему никто не указал на эту ошибку, которую я взял почти 2 ночи, чтобы узнать решение.

OLD CODE (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];
}

Ответ 3

Это было хорошо обсуждено, но у меня есть одна вещь, которую нужно добавить. Подумайте, почему вы назначили делегата распознавателей жестов. В моем случае это было связано с тем, что в некоторых случаях я хотел предотвратить распознавание распознавателей жестов с делегатом gestureRecognizerShouldBegin:.

Но в iOS 6, где возникает эта проблема, есть совершенно новый способ сделать именно это, реализовав gestureRecognizerShouldBegin: в UIView. (Это новый метод экземпляра UIView в iOS 6.)

Таким образом, я смог выполнить то, что я делал раньше, не изменяя делегата распознавателей жестов.

Ответ 4

У меня возникла проблема с сбоем UIPageViewController с iOS6 с той же ошибкой ( "Количество предоставленных контроллеров представления (0) не соответствует требуемому числу (1) для запрошенного перехода" ).

Ни одно из вышеперечисленных решений не работало для меня, но в итоге я обнаружил, что перемещение следующей строки от viewDidLoad до viewDidAppear исправлено.

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

Ответ 5

В целом же проблема здесь.

То, что я сделал, было исправлением, которое возвращает только клон before/afterViewController вместо nil, т.е.

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

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

Это означает, что вы можете скручивать страницы навсегда, но у меня не было другого выбора... Лучшее решение всегда приветствуется.