使用UITableViewCell子类执行-layoutSubviews后仍需要“自动布局”

时间:2012-09-26 21:32:52

标签: objective-c ios xcode4.5 autolayout

使用XCode 4.5和iOS 6,我正在开发一个带有自定义单元格的简单表视图的应用程序。我已经在iOS 5及以下版本中完成了这一百次,但出于某种原因,新的autoLayout系统给我带来了很多麻烦。

我在IB中设置了我的表格视图和原型单元格,添加了子视图并将它们连接起来作为IBOutlets然后设置我的委托和dataSource。但是现在每当从cellForRowAtIndexPath获取第一个单元格时,我都会收到以下错误:

  

***断言失败 - [ShopCell layoutSublayersOfLayer:],/ SourceCache / UIKit_Sim / UIKit-2372 / UIView.m:5776

     

***因未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'执行-layoutSubviews后仍需要自动布局。 ShopCell的-layoutSubviews实现需要调用super。'

我没有在我的子类化单元格(ShopCell)中实现-layoutSubviews方法,即使我尝试这样做并添加超级调用,因为它表明我仍然得到相同的错误。如果我从IB中的单元格中删除子视图,并将其更改为标准的UITableViewCell,一切都按预期工作,但当然我的单元格中没有数据。

我几乎可以肯定我有一些简单的东西,但我找不到任何文件或指南来暗示我做错了什么。任何帮助将不胜感激。

编辑:尝试将其更改为IB中的UITableViewCell并保留所有子视图,仍然是相同的错误。

31 个答案:

答案 0 :(得分:57)

我在代码中手动添加约束时遇到了同样的问题。在代码中,我正在执行以下操作:

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

<强>假设

据我所知,问题是当你禁用translatesAutoresizingMaskIntoConstraints时,UITableViewCell开始使用自动布局并自然失败,因为layoutSublayersForLayer的底层实现不会调用super。使用Hopper或其他工具的人可以证实这一点。既然你正在使用IB,你可能想知道为什么这是一个问题...那是因为使用IB会自动禁用translatesAutoresizingMaskIntoConstraints来为它添加约束的视图(它会自动在其中添加宽​​度和高度约束)位)。

<强>解决方案

我的解决方案是将所有内容移至contentView

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

我不是百分百确定这是否可以在Interface Builder中运行,但是如果你把所有东西都推出你的单元格(假设你有直接的东西)那么它应该可行。希望这能帮到你!

答案 1 :(得分:53)

显然,UITableViewCell的layoutSubviews实现不会调用super,这是自动布局的问题。我有兴趣看看是否将以下类别放入项目中可以解决问题。它帮助了一个测试项目。

#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

我可能会在表格单元格上使用backgroundView时添加问题,因为它会作为子视图添加到单元格中(而大多数子视图应该添加到表格单元格的contentView中,通常应该更好)

注意:在iOS7中修复了此错误;我能够删除这段代码,或者至少添加一个运行时检查,这样只有在iOS6上运行才能完成。

答案 2 :(得分:33)

我有几个月的同样的错误。但是我发现了问题所在。

创建IB文件时,已添加UIView。如果您使用此视图,则在禁用自动布局时应用程序不会崩溃(但还有其他问题)。使用自动布局时,您必须在对象库中选择正确视图:UITableViewCell

事实上,您应始终使用此项,因为所有子视图都已添加到contentView的{​​{1}}。

这就是全部。一切都会好的。

答案 3 :(得分:17)

我在使用自定义UITableViewHeaderFooterView + xib时遇到了同样的问题。

我在这里看到了一些答案,但我发现自定义页脚视图类中的实现-layoutSubviews修复了问题:

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

答案 4 :(得分:15)

在iOS 7中遇到同样的问题(iOS 8似乎已修复)。我的解决方案是在[self.view layoutIfNeeded]方法结束时调用viewDidLayoutSubviews

答案 5 :(得分:15)

我看到这是修改layoutSubviews实现中的约束的结果。从方法的开头到结尾将调用移动到super修复了问题。

答案 6 :(得分:14)

我有同样的问题。问题在于我创建单元格Xib的方式。我创建了一个像普通的Xib,只是将默认的“UIView”的类型更改为我的自定义UITableViewCell类。正确的方法是先删除默认视图,然后将表视图单元格对象拖到xib上。更多详情:http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/

答案 7 :(得分:7)

我通过为自定义表视图单元格的所有子视图关闭“Autolayout”解决了这个问题。

在自定义单元格的xib中,选择一个子视图并取消选中File Inspector&gt; Interface Builder Document&gt;使用Autolayout

答案 8 :(得分:7)

我有一个类似的问题不在UITableViewCell上,而是在UITableView本身。因为这是谷歌的第一个结果,我会在这里发布。事实证明viewForHeaderInSection是问题所在。我创建了UITableViewHeaderFooterView并将translatesAutoresizingMaskIntoConstraints设置为NO。现在有了一个有趣的部分:

iOS 7:

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

如果我这样做,应用程序会崩溃

  

执行-layoutSubviews后仍需要自动布局。   UITableView的-layoutSubviews实现需要调用super。

好的,我认为你不能在表视图标题上使用自动布局,只能在子视图上使用。但这不是你后来看到的全部真相。 总结一下:请勿在iOS 7上禁用自动调整大小的屏幕。否则它正常工作。

iOS 8:

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

如果我不使用它,我会得到以下输出:

  

无法同时满足约束条件。

对于iOS 8,您必须为标题禁用自动调整大小屏幕。

不知道为什么它会以这种方式表现,但似乎Apple确实修复了iOS 8中的一些内容,并且自动布局在iOS 7和iOS 8上的工作方式不同。

答案 9 :(得分:5)

如上所述,当您创建一个在UITableView中使用的视图时,您必须删除默认创建的视图,并将UITableViewCell或UITableViewHeaderFooterView作为根视图拖动。 但是,有一种方法可以修复XIB以防错过该部分。您必须在文本编辑器和根标记中打开XIB文件,并且直接子项添加/更改属性translatesAutoresizingMaskIntoConstraintsYES,例如

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

答案 10 :(得分:2)

我遇到了这个问题,它似乎与UITableViewCell子类有关,因为它们特别添加了其他自定义UIView子类的原型单元格。我在这里强调“习惯”,因为我已经成功使用了只有UIKit子元素的单元格,但是在尝试为我创建的视图构建约束时会失败,抛出作者问题中陈述的错误。

我不得不将我的单元格分成不使用AutoLayout的独立笔尖。

让我们希望苹果清理这个烂摊子。

答案 11 :(得分:2)

将您的子视图添加到单元格的contentView而不是单元格本身。 所以而不是:

[self addSubview:someView];

你必须使用

[self.contentView addSubview:someView];

答案 12 :(得分:1)

我通过将backgroundView连接器从我的UIImageView自定义accessoryViewUIButton连接器中解除连接来消除此错误。我怀疑这些并不是按照我使用它的方式使用的。

答案 13 :(得分:1)

我今天第一次遇到这个问题。到目前为止,我在使用原型UITableViewCell子类方面有一些不同的经验,但从未遇到过这个问题。我正在使用的单元格的不同之处在于我有一个IBOutlet到-backgroundView,我用它来为单元格着色。我发现,如果我创建了一个新属性并且仍然添加了一个新的UIView,它延伸了整个单元格的范围,那么这个断言就消失了。为了验证这是原因,我回到将此视图附加到backgroundView插座并重新出现断言。到目前为止,自从我做了这个更改以来,在子类原型UITableViewCell中使用AutoLayout没有其他问题。

答案 14 :(得分:1)

我遇到过这个,因为我最初在Uib文件中添加了UIView而不是UITableViewCell。

答案 15 :(得分:1)

我没有为此问题找到任何正确的解决方案,但您可以通过使用框架修复它,而不是将translatesAutoresizingMaskIntoConstraints属性设置为否(默认为是,所以不要设置它)

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];

答案 16 :(得分:0)

我修改了Carl Lindberg's answer来覆盖UITableView而是开始为我工作:

<强>的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

然后在MyViewController.m我刚刚导入了类别:

#import "UITableView+AutoLayoutFix.h"

答案 17 :(得分:0)

解决方案: 在调用super layoutSubviews

之前更改约束
- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

答案 18 :(得分:0)

问题是对子视图的布局调用的排序:

Check out

显示在 iOS&lt; 8

答案 19 :(得分:0)

我在IB中遇到了与静态表格视图单元类似的问题。其中一个单元格的子视图有一个被错误地改为UITextfield子类的类。编译器没有给出任何警告/错误。但是在运行时,系统无法加载视图控制器,导致上述崩溃。

答案 20 :(得分:0)

我去了同样的问题。我去了我的DetailViewController并将标识符重命名为UIView。它以前在UITableView上。它解决了这个问题。此问题不必在您的DetailViewController中。它可以是任何其他的。尝试将其重命名为受尊重的标识符。

答案 21 :(得分:0)

我遇到了同样的问题,最后发现原因是我向UITableViewCell添加了一个约束,UITableViewCell应该是UITableViewCell的 contentView 。当我改变约束时一切都很顺利!

答案 22 :(得分:0)

我在Xcode 6,iOS 7+中设置的表格页脚视图有一个非常类似的问题。 解决方案是nib文件的格式。显然它被卡在Xcode 4格式或其他东西。 将文件设置更改为&#34;打开:Xcode 6.0&#34; (或默认,就此而言),立即修复它。 偶然找到解决方案:它让我发疯,所以我删除了整个文件并再次创建,显然是使用默认设置。我不知道为什么简单地编辑最新Xcode中的文件并没有像往常那样将其转换为Xcode 5+格式。

f

答案 23 :(得分:0)

我遇到了同样的问题。这是我的项目的问题:
当我使用Interface Builder创建自定义UITableViewCell时,我从Xcode的对象集合窗格中拖动 View 而不是 Table View Cell 作为自定义表格单元格 如果你处于同样的情况,这里有解决方案:
删除界面构建器中的视图,确保从对象集窗格中拖动表视图单元格并重做自定义表格单元格视图。您可以复制旧视图中的对象,并将它们粘贴到新的表视图单元格的画布上。

答案 24 :(得分:0)

忘记在[super viewDidAppear:]内拨打viewDidAppear可能会导致此问题,但我确信这不是唯一原因。

答案 25 :(得分:0)

当我使用故事板创建自定义UITableViewCell时遇到了同样的问题。幸运的是我发现了问题,因为我将accessoryView([UITableViewCell setAccessoryView:])输出到我添加到单元格的UIButton。

  

所以当我在iOS6上运行时,它出现在我的项目中。

<强>解决方案

  

我在accessoryView和我的按钮之间释放插座   包含自定义单元格。

<强>提案

  

您不应该使用UITableViewCell的原生元素并进行更改   它

答案 26 :(得分:0)

我找到了解决方案。

就我而言,我在storyboard中创建了cell的视图(启用了自动布局),我在ViewController.m中定义了自定义UITableViewCell接口,我必须将接口移到ViewController.h。

答案 27 :(得分:0)

就我而言,

UITableView自动布局的引用UIImageView被分配给UITableView的backgroundView。

self.tableView.backgroundView = self.tableBackgroundImageView;

因此,我从UIView(Root视图)中删除了用于backgroundView的UIImageView,并重置(删除)对该UIImageView的所有自动布局引用。我在UIView(根视图)的外部放置了UIImageView背景。然后在代码中分配给UITableView的backgroundView。

然后修复。

答案 28 :(得分:0)

在某些情况下,这可以轻松解决布局问题(取决于您的布局)。在你的UITableView子类中,在awakeFromNib或init中,设置自动调整掩码:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

通过defaut,它被设置为UIViewAutoresizingNone

答案 29 :(得分:0)

我一直在经历同样的事情。事实证明,如果您以编程方式从ShopCell .xib / storyboard添加子视图(使用自动布局)作为另一个视图的子视图,则可能会抛出该异常,具体取决于您的约束的配置方式。我的猜测是,在IB中创建的约束是以编程方式将视图添加为子视图时产生的麻烦,因为它随后维护来自viewA的约束 - &gt;同时您可以将viewB添加为viewC的子视图。你得到了(那句话甚至让我自己感到困惑)?

在我的情况下 - 由于导致问题的视图非常简单 - 我以编程方式而不是IB创建了视图。这解决了它。您可以将这些视图提取到其他xib文件,并为这些文件禁用自动布局。我猜这有用。

答案 30 :(得分:-1)

我有同样的问题,从UIView更改为UITableViewCell解决了这个问题。