问题
While switching between Tabs too fast in UIPageViewController, App getting crash in line
[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:]
with errors Assertion failure and Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No view controller managing visible view.
Error Log as below
*** Assertion failure in -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /SourceCache/UIKit/UIKit-3318.0.1/UIPageViewController.m:1875
2014-09-29 11:34:00.770 Wowcher[193:9460] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No view controller managing visible view <UIView: 0x1783fa80; frame = (0 0; 320 416); autoresize = W+RM+H+BM; layer = <CALayer: 0x17898540>>'
*** First throw call stack:
(0x219fbf87 0x2f15ac77 0x219fbe5d 0x226cb2c9 0x253f9fff 0x2546f8d3 0x2546f6b7 0x2546c2b9 0x254700db 0x25470f97 0x2546d037 0x24ea925f 0x2500a589 0x24ff7eef 0x24ea677d 0x252b8c81 0x24e70105 0x24e6e07f 0x24ea4b6d 0x24ea443d 0x24e7acc5 0x250ee513 0x24e79707 0x219c2807 0x219c1c1b 0x219c0299 0x2190ddb1 0x2190dbc3 0x28c99051 0x24ed9a31 0xd950b 0xca6e0)
libc++abi.dylib: terminating with uncaught exception of type NSException
Thanks in advance
回答1:
So my solution to this was adding a BOOL
which keeps track of my animations state. So before setting the new ViewController
, I modify this too:
if (!_transitionInProgress) {
_transitionInProgress = YES;
[self.pageController setViewControllers:@[viewController] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:^(BOOL finished) {
_transitionInProgress = !finished;
}];
}
So I'll wait for my animation to finish before setting a new view controller. In my case, I have a some buttons the user can press in order to switch pages. This also prevents them from going too fast through them so the animations are always smooth and nice
回答2:
This is a bug in the internal implementation of UIPageViewController in scroll mode. It happens when a transition animation occurs while the page view controller is already animating a transition. What I ended up doing was to block the UI from allowing multiple quick scrolls. I have two buttons, left and right, which make the page view controller scroll to previous or next page controller. I disable the buttons' operation while there is an animation going. The page view controller's delegate tells you all you need to know when to disable the UI's functionality and when to re-enable it, once all animations have stopped.
回答3:
I am also facing this problem, but the issue is that I am unable to consistently reproduce the problem, but I can see from the crashlogs that the issue exists.
I have the pageviewcontroller which allows the user to swipe and also the view scrolls programmatically. The app crashes sometimes when you just enter the screen, but in the next attempts it works fine, so its kind of crazy. Even if I put a fix I cant be sure that it works as I am unable to reproduce it. Looks like the below code should fix it (took from Removing a view controller from UIPageViewController) atleast the screen behaves better with this code. I would really appreciate if I can get some methods to inject this crash myself, so that I can verify the fix.
- (void) setViewControllers:(NSArray*)viewControllers direction:(UIPageViewControllerNavigationDirection)direction animated:(BOOL)animated completion:(void (^)(BOOL))completion {
if (!animated) {
[super setViewControllers:viewControllers direction:direction animated:NO completion:completion];
return;
}
[super setViewControllers:viewControllers direction:direction animated:YES completion:^(BOOL finished){
if (finished) {
dispatch_async(dispatch_get_main_queue(), ^{
[super setViewControllers:viewControllers direction:direction animated:NO completion:completion];
});
} else {
if (completion != NULL) {
completion(finished);
}
}
}];
}
回答4:
There is a really good discussion here:
Removing a view controller from UIPageViewController
The accepted answer discusses this:
"Not knowing exactly why this was happening, I backtracked and eventually started using Jai's answer as a solution, creating an entirely new UIPageViewController
, pushing it onto a UINavigationController
, then popping out the old one. Gross, but it works--mostly. I have been finding I'm still getting occasional Assertion Failures from the UIPageViewController
, like this one:
- Assertion failure in -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /SourceCache/UIKit_Sim/UIKit-2380.17/UIPageViewController.m:1820 $1 = 154507824 No view controller managing visible view >
And the app crashes. Why? Well, searching, I found this other question that I mentioned up top, and particularly the accepted answer which advocates my original idea, of simply calling setViewControllers: animated:YES
and then as soon as it completes calling setViewControllers: animated:NO
with the same view controllers to reset the UIPageViewController
, but it had the missing element: calling that code back on the main queue! Here's the code:"
回答5:
I fixed issue by setting edgesForExtendedLayout = UIRectEdgeNone
on my UIPageViewController
subclass:
- (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation options:(NSDictionary<NSString *,id> *)options
{
self = [super initWithTransitionStyle:style navigationOrientation:navigationOrientation options:options];
self.edgesForExtendedLayout = UIRectEdgeNone;
return self;
}
回答6:
I also faced the same situation and my app has both swipe and next & previous buttons to navigate back and forth. To fix the issue assign a local Bool variable set it to true while initializing (let's say private var canScroll: Bool = true) then check for condition in first line of your navigation method using guard then set the Bool value to false before setViewcontroller method. on completion of the animation set the same bool to true so that when you perform a swipe action while the view controller is transitioning the guard statement checks for canScroll to be true if not it returns. that's how you can avoid the crash issue in pagination below is my code for next action.
@IBAction func nextAction(_ sender: Any) {
guard canScroll == true else { return } //check condition
guard featureCount > 0 else { return }
guard let index = self.viewControllerAtIndex(indexRow) else { return }
let startingViewController: OnBoardModelViewController = index
canScroll = false
pageViewController?.setViewControllers([startingViewController],
direction: UIPageViewControllerNavigationDirection.forward,
animated: true,
completion: {_ in
self.canScroll = true
})
}
来源:https://stackoverflow.com/questions/25740245/assertion-failure-in-uipageviewcontroller