115
votes

Using XCode 4.5 and iOS 6, I'm developing an app with a simple table view with custom cells. I've done this a hundred times in iOS 5 and below, but for some reason the new autoLayout system is giving me a lot of trouble.

I setup my table view and prototype cell in IB, added subviews and wired them up as IBOutlets then setup my delegate and dataSource. However now whenever the first cell is fetched from cellForRowAtIndexPath, I get the following error:

*** Assertion failure in -[ShopCell layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. ShopCell's implementation of -layoutSubviews needs to call super.'

I haven't implemented a -layoutSubviews method in my subclassed cell (ShopCell), and even when I try to do that and add the super call as it suggests I still get the same error. If I remove the subviews from the cell in IB, and change it to a standard UITableViewCell, everything works as expected, though of course I'm left with no data in my cells.

I'm almost certain that there's something simple I'm missing, but can't find any documentation or guides to suggest what I've done wrong. Any help would be appreciated.

Edit: Just tried changing it to a UITableViewCell in IB and leaving all the subviews in place, still the same error.

30
Try lldb [[UIWindow keyWindow] _autoLayoutTrace] at debugger area if automatic layout is used.A-Live
Are you using UIView for the custom cell instead of UITableViewCell ? I had the same problem. I had UIView for the custom cell and was adding sub views to that. Changed to UITableViewCell and it worked.user1705389
Hey mike, how are you defining the outlets? Are they properties in your implementation file in a class extension?kocodude
@A-Live Whenever I try to use that method I get an error in the debugger....is this method still valid? Edit: Nevermind, it is a lowercase l in autolayout.borrrden
uncheck the autoLayout box in inspector then clean and run. it will surly work.Nico

30 Answers

57
votes

I encountered the same problem while manually adding constraints in code. In code, I was doing the following:

{
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    [self addSubview:someView];
    [self addSubview:someOtherView];
    [self addConstraint:...];
}

Hypothesis

From what I can tell, the issue is that when you disable translatesAutoresizingMaskIntoConstraints, UITableViewCell starts to use Auto Layout and naturally fails because the underlying implementation of layoutSublayersForLayer does not call super. Someone with Hopper or some other tool can confirm this. Since you're using IB you're probably wondering why this is an issue... and that's because using IB automatically disables translatesAutoresizingMaskIntoConstraints for views that it adds constraints to (it will automatically add a width and height constraint in their place).

Solution

My solution was to move everything to the contentView.

{
   [self.contentView addSubview:someView];
   [self.contentView addSubview:someOtherView];
   [self.contentView addConstraint:...];
}

I'm not 100% sure if this will work in Interface Builder, but if you push everything off of your cell (assuming that you have something directly on it) then it should work. Hope this helps you!

53
votes

Apparently, UITableViewCell's layoutSubviews implementation does not call super, which is a problem with auto layout. I'd be interested to see if dropping the below category into projects fixes things. It helped in a test project.

#import <objc/runtime.h>
#import <objc/message.h>

@implementation UITableViewCell (FixUITableViewCellAutolayoutIHope)

+ (void)load
{
    Method existing = class_getInstanceMethod(self, @selector(layoutSubviews));
    Method new = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews));

    method_exchangeImplementations(existing, new);
}

- (void)_autolayout_replacementLayoutSubviews
{
    [super layoutSubviews];
    [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling
    [super layoutSubviews];
}

@end

I might add the problem showed up for me when using a backgroundView on the table cell, as that gets added as a subview to the cell (whereas most subviews should be added to the table cell's contentView, which should usually work better).

Note: It appears this bug is fixed in iOS7; I was able to remove this code, or at least add a runtime check so that it's only done if running on iOS6.

33
votes

I had the same bug for few months. But I found what was the problem.

When I create an IB file, a UIView is already added. If you use this view, the app doesn't crash when auto layout is disabled (but there are other issues). When you use auto layout, you have to select the right view in the Object Library : UITableViewCell.

In fact, you should always use this item because all subviews are added to the contentView of the UITableViewCell.

That's all. All will be fine.

17
votes

I had same trouble with custom UITableViewHeaderFooterView + xib.

I saw some answers here, but I found what implementation -layoutSubviews in my custom footer view class fixes issue:

-(void)layoutSubviews
{
    [super layoutSubviews];
    [self layoutIfNeeded]; // this line is key
}
15
votes

I was seeing this as a result of modifying constraints in my implementation of layoutSubviews. Moving the call to super from the beginning to the end of the method fixed the problem.

15
votes

Had the same problem in iOS 7 (iOS 8 seems to fix). The solution for me was to call [self.view layoutIfNeeded] at the end of my viewDidLayoutSubviews method.

14
votes

I had the same issue. The problem was in the way I was creating the cell Xib. I created a Xib like normal and just changed the type of the default "UIView" to my custom UITableViewCell class. The correct way to is to first delete the default view and then drag the table view cell object onto the xib. More details here : http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/

7
votes

I resolved the issue by turning off "Autolayout" for all the subviews of my custom Table View Cell.

In the xib for a custom cell, select a subview and uncheck File Inspector > Interface Builder Document > Use Autolayout

7
votes

I had a similar problem not on UITableViewCell but rather on UITableView itself. Because it is the first result in Google I'll post it here. It turned out that viewForHeaderInSection was the problem. I created a UITableViewHeaderFooterView and set translatesAutoresizingMaskIntoConstraints to NO. Now here comes the interesting part:

iOS 7:

// don't do this on iOS 7
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

If I do this the app crashes with

Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.

OK, I thought you can't use auto layout on a table view header and only on the subviews. But that's not the full truth as you see it later. To sum up: Don't disable auto resizing mask for the header on iOS 7. Otherwise it's working fine.

iOS 8:

// you have to do this, otherwise you get an auto layout error
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

If I wouldn't use this I'd get the following output:

Unable to simultaneously satisfy constraints.

For iOS 8 you have to disable auto resizing mask for the header.

Don't know why it behaves in this way but it seems that Apple did fix some things in iOS 8 and auto layout is working differently on iOS 7 and iOS 8.

5
votes

As someone above has already stated, when you create a view for use in a UITableView, you have to delete the view created by default and drag a UITableViewCell or UITableViewHeaderFooterView as the root view. However, there is a way to fix the XIB in case you had missed that part. You have to open the XIB file in a text editor and in the root tag and its direct child add/change the attribute translatesAutoresizingMaskIntoConstraints to YES, for example

<view contentMode="scaleToFill" horizontalHuggingPriority="1000" id="1" translatesAutoresizingMaskIntoConstraints="YES" customClass="MXWCollapsibleTableHeaderView">

2
votes

I am encountering this and it seems that it is related to UITableViewCell subclasses as prototype cells that specifically have other custom UIView subclasses added to them. I stress the 'custom' here because I have been successful with cells that just have UIKit children, but it falls over when trying to build the constraints for views I have created bespoke, throwing the error stated in the authors question.

I have had to separate my cells into independent nibs that don't use AutoLayout.

Let's hope Apple clean up this mess.

2
votes

Add your subviews to the contentView of the cell instead of the cell itself. So instead of:

[self addSubview:someView];

you must use

[self.contentView addSubview:someView];

1
votes

I encountered this one because I had initially added a UIView instead of a UITableViewCell to a xib file.

1
votes

I eliminated this error by uncoupling the backgroundView connector from my background UIImageView and accessoryView connector from my UIButton customisations. I suspect that these were not meant to be used the way I was using them.

1
votes

I had run into this issue first time today. Up until now I had some various experience in using prototype UITableViewCell subclasses but never ran into this issue. What was different about the cell I was working with was that I had an IBOutlet to the -backgroundView which I was using to color the cell. I found that if I created a new property and still added a fresh UIView which stretched the span of the entire cell, this assertion went away. To verify this was the cause, I went back to attaching this view to the backgroundView outlet and the assertion reappeared. So far, no other issues using AutoLayout in a subclassed prototype UITableViewCell since I've made this change.

1
votes

I didn't get any proper solution for this issue but you can fix it by using frames and not setting translatesAutoresizingMaskIntoConstraints property to No (by default its yes, so don't set it)

CGRect headerViewFrame = CGRectMake(0,0,320,60); //Frame for your header/footer view
UIView *tableHeaderView = [[UIView alloc] initWithFrame:headerViewFrame];
tableHeaderView.translatesAutoresizingMaskIntoConstraints = Yes; //Or don't set it at all
[self.tableView setTableHeaderView:tableHeaderView];
0
votes

I have been experiencing the same thing. It turned out that if you programmatically add a subview from your ShopCell .xib/storyboard, that uses auto layout, as a subview to another view, that exception might be thrown, depending on how your constraints are configured. My guess is that the constraints created in IB is what creates the troubles when programmatically adding a view as a subview, since it's then maintaing constraints from viewA --> viewB meanwhile you might add viewB as a subview of viewC. You got it (that sentence is even confusing myself)?

In my situation - since it was very simple views that caused the problem - I created the views programmatically and not in IB. That solved it. You might extract those views to other xib files and disable auto layout for those. I guess that'd work.

0
votes

In some situations, this solves the layout problem easily (depending on your layout). Inside you UITableView subclass, in either awakeFromNib or init, set the autoresizing mask:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

By defaut it is set to UIViewAutoresizingNone

0
votes

In my case,

The referenced UIImageView for the auto layout for UITableView is assigned to backgroundView of the UITableView.

self.tableView.backgroundView = self.tableBackgroundImageView;

So, I removed UIImageView for backgroundView from the UIView(Root view) and reset(remove) all auto layout reference to that UIImageView. I placed that UIImageView for background at the outside from the UIView(root view). And then assign to the backgroundView of the UITableView in code.

Then fixed.

0
votes

I have found the solution.

In my case, I created cell's view in storyboard (with auto layout enabled) and I defined the custom UITableViewCell interface in my ViewController.m, I have to move interface to ViewController.h.

0
votes

I encountered the same problem when I use the storyboard to create the custom UITableViewCell. Fortunately I found the problem, because I outlet the accessoryView([UITableViewCell setAccessoryView:]) to UIButton which I added to the cell.

So it occurred in my project when run on the iOS6.

Solution

I release the outlet between accessoryView and my button which contained the custom cell.

Proposal

You shouldn't used the UITableViewCell's native elements and change it.

0
votes

This problem can be caused by forgetting to call [super viewDidAppear:] within viewDidAppear, but I'm sure it's not the only cause.

0
votes

I had exact the same problem. Here is the problem with my project:
When I worked on the Interface Builder to create a custom UITableViewCell, I dragged a View instead of a Table View Cell from the object collection pane in Xcode
as the custom table cell.
If you are in the same situation, here is the solution:
Delete the view in interface builder, make sure you drag a Table View Cell from the object collection pane and redo the custom table cell view. You can copy the objects in the old view and paste them to the canvas for the new Table View Cell.

0
votes

I had a very similar problem with a table footer view I was setting in Xcode 6, iOS 7+. The solution was in the format of the nib file. Apparently it was stuck in Xcode 4 format or something. Changing the file settings to "opens in: Xcode 6.0" (or Default, for that matter), instantly fixed it. Found the solution by chance: it was driving me crazy, so I deleted the entire file and created again, obviously with the default settings. I have no idea why simply editing the file in the latest Xcode didn't convert it to a Xcode 5+ format, as it usually happens.

f

0
votes

I went had the same issue. I went to my DetailViewController and renamed the identifier to UIView. It was previously on UITableView. It fixed the problem. This problem doesn't have to be in your DetailViewController. It could be in any other one. Try renaming it to the respected identifier.

0
votes

I had a similar issue with static table view cells in IB. One of the cells had a subview that had a class that was mistakenly altered to a subclass of UITextfield. The compiler didn't give any warnings/errors. But at runtime the system was unable to load the view controller with the aforementioned crash as a result.

0
votes

Issue is sequencing of the layout calls to the subviews:

Check out

Shows up in iOS < 8

0
votes

Solution: change constraints before call super layoutSubviews

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}
0
votes

I modified Carl Lindberg's answer to override UITableView instead and it started working for me:

UITableView+AutoLayoutFix.h

@interface UITableView (AutoLayoutFix)
@end

UITableView+AutoLayoutFix.m

#import <objc/runtime.h>

@implementation UITableView (AutoLayoutFix)

+ (void)load
{
    Method existingMethod = class_getInstanceMethod(self, @selector(layoutSubviews));
    Method newMethod = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews));

    method_exchangeImplementations(existingMethod, newMethod);
}

- (void)_autolayout_replacementLayoutSubviews
{
    [super layoutSubviews];
    [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling
    [super layoutSubviews];
}

@end

Then in MyViewController.m I just imported the category:

#import "UITableView+AutoLayoutFix.h"
0
votes

I met the same problem and finally found the reason was that I added one constraint to the UITableViewCell, which should be the UITableViewCell's contentView. When I changed the constraint everything went fine!