115

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

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

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

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

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

我几乎可以肯定我缺少一些简单的东西,但是找不到任何文档或指南来表明我做错了什么。任何帮助,将不胜感激。

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

4

31 回答 31

57

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

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

假设

据我所知,问题是当你禁用时translatesAutoresizingMaskIntoConstraints, UITableViewCell 开始使用 Auto Layout 并且自然会失败,因为底层实现layoutSublayersForLayer不调用 super. 使用 Hopper 或其他工具的人可以确认这一点。由于您使用的是 IB,您可能想知道为什么这是一个问题……那是因为使用 IB 会自动禁用translatesAutoresizingMaskIntoConstraints它添加约束的视图(它会自动在它们的位置添加宽度和高度约束)。

解决方案

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

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

我不能 100% 确定这是否会在 Interface Builder 中工作,但如果你将所有东西都从你的单元格中推出(假设你直接在上面有东西),那么它应该可以工作。希望这对你有帮助!

于 2012-09-27T22:42:33.093 回答
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 上运行时完成。

于 2012-10-17T18:51:59.630 回答
33

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

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

实际上,您应该始终使用此项目,因为所有子视图都添加contentViewUITableViewCell.

就这样。一切都会好起来的。

于 2013-02-28T15:45:05.303 回答
17

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

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

-(void)layoutSubviews
{
    [super layoutSubviews];
    [self layoutIfNeeded]; // this line is key
}
于 2014-12-05T09:56:09.240 回答
15

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

于 2013-05-30T06:09:23.780 回答
15

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

于 2014-10-17T17:55:51.690 回答
14

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

于 2013-04-05T22:06:13.600 回答
7

我有一个类似的问题,UITableViewCell而不是它UITableView本身。因为这是谷歌的第一个结果,所以我会在这里发布。原来这viewForHeaderInSection就是问题所在。我创建了一个UITableViewHeaderFooterView并设置translatesAutoresizingMaskIntoConstraintsNO. 现在有趣的部分来了:

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 上的工作方式不同。

于 2014-11-11T12:59:43.330 回答
7

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

在自定义单元格的 xib 中,选择一个子视图并取消选中 File Inspector > Interface Builder Document > Use Autolayout

于 2013-02-14T11:11:04.370 回答
5

正如上面有人已经说过的,当您创建用于 UITableView 的视图时,您必须删除默认创建的视图并将 UITableViewCell 或 UITableViewHeaderFooterView 作为根视图。但是,如果您错过了该部分,有一种方法可以修复 XIB。您必须在文本编辑器中打开 XIB 文件,并在根标签及其直接子标签中将属性添加/更改translatesAutoresizingMaskIntoConstraintsYES,例如

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

于 2014-01-30T20:39:16.250 回答
2

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

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

让我们希望 Apple 收拾这个烂摊子。

于 2013-02-28T17:00:41.907 回答
2

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

[self addSubview:someView];

你必须使用

[self.contentView addSubview:someView];

于 2013-05-28T15:12:28.113 回答
1

我没有为这个问题找到任何适当的解决方案,但您可以通过使用框架来修复它,而不是将 translatesAutoresizingMaskIntoConstraints 属性设置为 No(默认情况下是,所以不要设置它)

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];
于 2014-07-28T14:26:09.093 回答
1

backgroundView我通过将连接器与我的背景UIImageViewaccessoryView连接器从我的自定义项中解耦来消除此错误UIButton。我怀疑这些并不是我使用它们的方式。

于 2013-03-22T03:57:38.823 回答
1

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

于 2013-04-16T23:06:41.407 回答
1

我遇到这个是因为我最初将 UIView 而不是 UITableViewCell 添加到 xib 文件中。

于 2013-02-25T15:59:17.190 回答
0

这个问题可能是由于忘记调用[super viewDidAppear:]within引起的viewDidAppear,但我确信这不是唯一的原因。

于 2014-07-28T20:20:04.473 回答
0

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

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

默认设置为 UIViewAutoresizingNone

于 2013-09-18T23:11:30.680 回答
0

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

于 2015-02-09T06:35:54.047 回答
0

我找到了解决方案。

在我的例子中,我在情节提要中创建了单元格的视图(启用了自动布局),并在我的 ViewController.m 中定义了自定义 UITableViewCell 接口,我必须将接口移动到 ViewController.h。

于 2014-07-05T11:34:25.947 回答
0

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

于 2014-09-19T02:01:48.690 回答
0

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

于 2015-03-05T13:40:13.400 回答
0

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

查看

iOS < 8中显示

于 2015-03-16T12:52:27.297 回答
0

我在使用情节提要创建自定义 UITableViewCell 时遇到了同样的问题。幸运的是我发现了问题,因为我将附件视图([UITableViewCell setAccessoryView:])输出到我添加到单元格的 UIButton 。

所以它发生在我在iOS6上运行的项目中。

解决方案

我释放了附件视图和包含自定义单元格的按钮之间的插座。

提议

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

于 2014-07-16T06:29:07.527 回答
0

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

F

于 2014-10-16T09:54:04.703 回答
0

解决方案:在调用super layoutSubviews之前改变约束

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}
于 2015-03-19T09:52:50.170 回答
0

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

在我的情况下——因为它是导致问题的非常简单的视图——我以编程方式而不是在 IB 中创建了视图。那解决了它。您可以将这些视图提取到其他 xib 文件并禁用这些视图的自动布局。我想那会奏效。

于 2012-10-03T18:13:58.913 回答
0

就我而言,

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

self.tableView.backgroundView = self.tableBackgroundImageView;

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

然后固定。

于 2013-09-23T09:07:47.620 回答
0

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"
于 2015-08-21T22:41:18.113 回答
0

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

于 2016-08-25T03:00:27.310 回答
-1

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

于 2013-12-26T19:22:27.130 回答