I have a view controller that is setup with a UITableView in UIStoryboard. The UITableView is constrained to the SafeArea of the controller on all four sides.
It may seem that this question has been asked before, but each time I have found the question, it is because there are changes taking place in viewDidLayoutSubviews that cause the loop to occur. I have a blank implementation of viewDidLayoutSubviews and basic UITableViewCells (no nib). Yet in iOS 11, Xcode 9.2, flicking the tableview up causes viewDidLayoutSubviews to be called on an endless loop. This is my implementation:
- (void)viewDidLayoutSubviews {
NSLog(@"viewDidLayoutSubviews");
[super viewDidLayoutSubviews];
}
I cannot figure out for the life of me how this is happening.
Edit: The controller has a NavigationController and is the Master controller of a UISplitViewController, which is embedded in a BannerViewController (from iAdSuite example).
Edit: This happens on iOS 11 (up through 11.2) on ALL devices on the simulator. Does NOT happen iOS 10.3. viewDidLayoutSubviews
isn't even called in iOS 10.3. I get the same results when I simply use the Nav Controller with the UIViewController/TableView in place of the UISplitViewController/BannerViewController. So seems that the issue is not introduced there, but from something that is happening in iOS 11.
EDIT: So this is odd - seems it is happening only when large titles are selected for the navigation controller!
if (@available(iOS 11.0, *)) {
self.navigationController.navigationBar.prefersLargeTitles = YES;
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeAlways;
}
EDIT: This problem can be easily reproduced. I downloaded Apple's iAd Suite sample code, and used the SplitNavigationController project. I updated the project for iOS 11, including updating the storyboard to use Safe Area Layout Guides. I changed the MasterViewController from a UITableViewController to a UIViewController with a UITableView, which I constrained to the Safe Area layout guides in the storyboard. I added in prefersLargeTitles and largeTitleDisplayMode to the MasterViewController. I added in the viewDidLayoutSubviews method, with a NSLog statement, so this behavior can be easily observed. I think this is a real problem with iOS 11, and I will try to get to the bottom of it, and I would also appreciate if anyone else can offer any thoughts or suggestions.
EDIT: matt was able to reproduce this issue and post it in a GitHub project, to be found at the following link (thanks matt!): InfiniteLayoutSubviewsBug
EDIT This was definitely a bug in iOS 11 thru at least iOS 11.2, but in iOS 12 the bug no longer exists.
It looks like you've found a bug. I was able to reproduce the problem in a minimal example project, which I've posted at GitHub here:
https://github.com/mattneub/InfiniteLayoutSubviewsBug
Download the project and run it. You'll see a simple table with three rows. Scroll the table view up and let go. Watch the console. We are getting repeated calls to
viewDidLayoutSubviews
, once every 1/60 of a second, forever.Note that this is not caused by a recursive layout loop in our code. My example doesn't even call
super
. All it does is log. This is the runtime itself callingviewDidLayoutSubviews
repeatedly forever. No code of ours (exceptprint
) runs while this is happening.Other observations:
As you rightly observed, if you change the example so that the navigation bar doesn't use large titles, the problem goes away.
If you change the example so that the table view is not positioned using autolayout, the problem goes away.
If you change the example (rather more elaborately) so that the view controller is a UITableViewController subclass, the problem goes away; we get some repeated calls to
viewDidLayoutSubviews
but not forever, just while scrolling.