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


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实现需要调用超级。”

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

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

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


lldb [[UIWindow keyWindow] _autoLayoutTrace]如果使用自动布局,请尝试在调试器区域。
A-Live

3
您是否使用UIView代替UITableViewCell作为自定义单元格?我有同样的问题。我有用于自定义单元格的UIView,并为此添加了子视图。更改为UITableViewCell并起作用。

嗨,迈克,您如何定义网点?它们是您的实现文件中类扩展的属性吗?
kocodude 2012年

@ A-Live每当我尝试使用该方法时,调试器中都会出现错误....此方法仍然有效吗?编辑:没关系,它是自动布局中的小写字母l。
borrrden 2012年

取消选中检查器中的“自动布局”框,然后清理并运行。它将正常工作。
Nico

Answers:


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:...];
}

我不确定100%是否可以在Interface Builder中使用,但是如果您将所有内容从单元格中推送出去(假设您直接在其上放置了东西),那么它应该可以使用。希望这对您有所帮助!


4
我还需要添加subview.translatesAutoresizingMaskIntoConstraints = NO'要添加到contentView的每个子视图。
杰伊·派耶

5
这对我有用。另外,请确保您要求self.contentView.translatesAutoresizingMaskIntoConstraints = NO输入UITableViewCell
Maurizio

53

显然,UITableViewCell的layoutSubviews实现不会调用超级,这是自动布局的问题。我想看看将以下类别放到项目中是否可以解决问题。它有助于测试项目。

#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上运行时才能完成。


奇怪的是,对于我来说,使用普通的UITableViewCell可以正常工作,但不适用于子类...
borrrden 2012年

您可能会认为,但是我所拥有的只是一个init方法,其他>>。我一生中从未覆盖过layoutSubviews哈哈。我认为问题在于UITableViewCell用作根视图的自定义视图无法使用自动布局,因为它会覆盖layoutSubviews(因此当您尝试向根视图添加约束时,它将失败)
borrrden 2012年

6
UITableView出于同样的原因,我不得不在iOS 6.1 b1 上创建此类类别
Joshua J. McKinnon 2012年

5
由于iOS 7中仍然存在该问题,TableHeaderView是否有类似的解决方法?
Softlion

1
这很好。尝试在UITableView中居中UIVIew子视图时遇到此问题。即使在iOS 7中,也会发生断言。但是它在iOS 8中不会发生,因此他们必须已经解决了该错误。
约旦H

33

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

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

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

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


这不应该被接受,因为问题不在于使用IB的实现,而且当您不使用IB时可能会发生此问题。如果您以编程方式查看视图,则@PhilLoden的答案更可行。
埃里克

我不明白答案。有人可以更清楚地解释吗?谢谢
hasan 2014年

我认为我有权利。检查课程att是否足够。在界面生成器中的身份检查器中?或添加的是另一种类型和类别的att。以后更新了吗?那还会引起问题吗?
hasan 2014年

@ hasan83您实际上可以返回单元格。UITableViewCell基本上是具有重用标识符的UIView。
2014年

17

我在使用custom UITableViewHeaderFooterView+ xib时遇到了同样的麻烦。

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

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

1
请注意,这可能会导致无限循环,并最终导致 EXC_BAD_ACCESS KERN_PROTECTION_FAILURE
mbi

15

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


这对我有用。我有一个自定义的UICollectionViewCell,我正在layoutSubviews中对其进行格式化。有人知道为什么这种解决方案有效吗?
STANGMMX

@ STANGMMX,A'sa Dickens的回答解释了原因。
法比奥·奥利维拉

15

在iOS 7中出现了相同的问题(iOS 8似乎已修复)。对我来说,解决方案是[self.view layoutIfNeeded]viewDidLayoutSubviews方法结尾处调用。


谢谢。它对我有帮助。我昨天(在iOS 7上)遇到了这个问题。它适用
Alexander

@MaciejSwic在顶部看到我的答案。
Sound Blaster 2014年

这对我有用!将iOS 7.1与Swift结合使用。我正在删除并在viewDidLayoutSubviews上添加了约束。我删除了超级呼叫,但仍然无法正常工作,但此解决方案成功了!给这个恐龙一片叶子!:)
jomafer'3

也使用iOS 7.1为我工作!
fdlr 2015年

14

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


1
完美的洞察力!我花了很长时间才意识到这一点,特别是因为如果我使用禁用了AutoLayout的UIView,我的应用程序不会崩溃。
Guilherme 2013年

超!另请参见下面的
@Arnaud回复

7

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

在定制单元的xib中,选择一个子视图,然后取消选中File Inspector> Interface Builder Document> Use Autolayout


4
我也一样 但是,如果您要使用自动布局,则不是真正的解决方案
ajmccall

7

我有一个类似的问题,不是UITableViewCellUITableView自身上,而是在自身上。因为这是Google的第一个结果,所以我将其发布在这里。原来那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,您必须禁用标题的自动调整大小掩码。

不知道为什么会这样,但苹果似乎确实在iOS 8中修复了某些问题,并且自动布局在iOS 7和iOS 8上的工作方式有所不同。


交配,您只是保存我的一天!
MarcinMałysz2015年

5

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

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


2

我遇到了这种情况,似乎它与UITableViewCell子类有关,它们是作为原型单元格而专门添加了其他自定义UIView子类的。我在这里强调“自定义”是因为我已经成功处理了只有UIKit子级的单元,但是在尝试为我创建的视图建立约束时会失败,从而抛出了作者问题中指出的错误。

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

让我们希望苹果能解决这一问题。



1

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


1

我通过取消backgroundView连接器与背景UIImageViewaccessoryViewUIButton定义项的连接器来消除此错误。我怀疑这些内容不是要以我使用它们的方式使用。


1

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


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

0

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

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


0

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

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

通过默认,将其设置为UIViewAutoresizingNone


这解决了我面临的问题。我正在使用表格单元格中的自动布局并结合[tableViewCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height以获取高度,然后在中使用heightForRowAtIndexPath
NathanAldenSr

0

就我而言

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

self.tableView.backgroundView = self.tableBackgroundImageView;

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

然后修复。


0

我找到了解决方案。

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


0

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

因此,在iOS6上运行时,它发生在我的项目中。

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

提案

您不应该使用UITableViewCell的本机元素并进行更改。


0

此问题可能是由于忘记在[super viewDidAppear:]内部调用而引起的viewDidAppear,但我确定这不是唯一的原因。


0

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


0

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

F


0

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


0

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



0

解决方案:在调用超级layoutSubviews之前更改约束

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

0

我修改了卡尔·林德伯格(Carl Lindberg)的答案以改为覆盖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"

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.