UIPageViewController в iOS6
В iOS6 в методах viewControllerAfterViewController и viewControllerBeforeViewController, если я возвращаю nil (для блокирования навигации по страницам, когда я на первой или последней странице), сбой приложения с этим исключение:
'Число доступных контроллеров представления (0) не соответствует требуемому числу (1) для запрошенного перехода
В iOS5 все работает хорошо.
Ответы
Ответ 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];
Это означает, что вы можете скручивать страницы навсегда, но у меня не было другого выбора...
Лучшее решение всегда приветствуется.