"Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass "Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass ios ios

"Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass


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!


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.


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.