I have a UIPageViewController
subclass, and in its viewDidLoad
I want to add a UILabel
to its self.view
. This works fine if I set its position using frames, but if I try to position it using Auto Layout, I get:
* Assertion failure in -[_UIPageViewControllerContentView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.58/UIView.m:8742
How am I supposed to position this UILabel to show up in the UIPageViewController
?
This seems to be happening because UIPageViewController
's view (which is actually a _UIPageViewControllerContentView
) doesn't handle subviews and autolayout as expected (at least in iOS 7; it worked fine for me in iOS 8).
You can get around this by not using autolayout, but I wanted to use autolayout so I ended up redoing my view controllers to avoid adding subviews to UIPageViewController
.
Instead of subclassing UIPageViewController
, I created a container view controller (a subclass of UIViewController
) with a UIPageViewController
as a child view controller. The custom subviews that I initially had in UIPageViewController
were then added to the container's view
. I also made the container the data source and delegate for the UIPageViewController
.
There's a related thread where people got the same assertion failure but with a UITableViewCell
: "Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass. Most of the suggestions there don't work or aren't applicable to UIPageViewController, but it helped me figure out why adding subviews with autolayout might cause a problem.
You can also subclass UIPageViewController and implement this workaround:
#import <objc/runtime.h>
@interface MyPageViewController : UIPageViewController
@end
@implementation MyPageViewController
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self applyLayoutSubviewsWorkaroundIfNeeded];
}
- (void)applyLayoutSubviewsWorkaroundIfNeeded {
// UIPageViewController does not support AutoLayout in iOS7, we get the following runtime error
// "_UIPageViewControllerContentView’s implementation of -layoutSubviews needs to call super…"
// This workaround calls the missing layoutSubviews method of UIView.
if ([self iOSVersionIsLowerThan8]) {
IMP uiviewLayoutSubviewsImplementation = class_getMethodImplementation([self.view class], @selector(layoutSubviews));
typedef void (*FunctionFromImplementation)(id, SEL);
FunctionFromImplementation uiviewLayoutSubviewsFunction = (FunctionFromImplementation)uiviewLayoutSubviewsImplementation;
uiviewLayoutSubviewsFunction(self.view, @selector(layoutSubviews));
}
}
- (BOOL)iOSVersionIsLowerThan8 {
// This is just one way of checking if we are on iOS7.
// You can use whatever method suits you best
return ![self respondsToSelector(popoverPresentationController)];
}
@end