【问题标题】:"Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass使用 UITableViewCell 子类执行“-layoutSubviews”后仍需要自动布局
【发布时间】:2012-09-18 14:43:21
【问题描述】:

使用 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 并保留所有子视图,仍然是同样的错误。

【问题讨论】:

  • 如果使用自动布局,请在调试器区域尝试lldb [[UIWindow keyWindow] _autoLayoutTrace]
  • 您是否使用 UIView 作为自定义单元格而不是 UITableViewCell ?我有同样的问题。我有自定义单元格的 UIView 并正在向其中添加子视图。改成 UITableViewCell 就可以了。
  • 嘿迈克,你是如何定义网点的?它们是类扩展中实现文件中的属性吗?
  • @A-Live 每当我尝试使用该方法时,我都会在调试器中收到错误....此方法仍然有效吗?编辑:没关系,它是自动布局中的小写 l。
  • 取消选中检查器中的自动布局框,然后清理并运行。它会很有效的。

标签: objective-c ios xcode4.5 autolayout


【解决方案1】:

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

{
    [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 中工作,但如果你将所有东西都从你的单元格中推出(假设你直接在上面有东西),那么它应该可以工作。希望对您有所帮助!

【讨论】:

  • 我还需要在添加到 contentView 的每个子视图上添加 subview.translatesAutoresizingMaskIntoConstraints = NO'
  • 这对我有用。另外,请确保您UITableViewCell 调用self.contentView.translatesAutoresizingMaskIntoConstraints = NO
【解决方案2】:

显然UITableViewCell的layoutSubviews实现没有调用super,这是auto layout的问题。我很想看看将以下类别放入项目中是否可以解决问题。它帮助了一个测试项目。

#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 中,这通常应该会更好) .

注意:这个bug似乎在iOS7中修复了;我能够删除此代码,或者至少添加一个运行时检查,以便仅在 iOS6 上运行时完成。

【讨论】:

  • 奇怪的是,它对我来说与普通的 UITableViewCell 一起工作得很好,只是不适用于子类......
  • 你会这么想,但我只有一个 init 方法,没有别的 ><. layoutsubviews uitableviewcell>
  • 出于同样的原因,我不得不在UITableView 上创建这样一个类别(iOS 6.1 b1)
  • TableHeaderView 是否有类似的修复,因为问题仍然存在于 ios 7 中?
  • 这很好用。当我尝试在 UITableView 中居中 UIVIew 子视图时遇到了这个问题。即使在 iOS 7 中也会发生断言。但它不会出现在 iOS 8 中,所以他们一定已经解决了这个错误。
【解决方案3】:

几个月来我一直遇到同样的错误。但我发现了问题所在。

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

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

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

【讨论】:

  • 这不应该是公认的答案,因为这个问题与使用 IB 的实现无关,而且当您不使用 IB 时可能会发生此问题。如果您以编程方式提出意见,@PhilLoden 的答案更可行。
  • 我不明白答案。有人可以解释得更清楚吗?谢谢
  • 我想我有这个权利。检查班级 att 是否足够?在界面生成器的身份检查器中?或者添加的是另一种类型和类别的att。后来更新了吗?这也会导致问题吗?
  • @hasan83 您实际上可以返回单元格。 UITableViewCell 基本上是一个带有重用标识符的 UIView。
【解决方案4】:

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

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

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

【讨论】:

  • 请注意,这可能会导致无限循环并最终导致 EXC_BAD_ACCESS KERN_PROTECTION_FAILURE
【解决方案5】:

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

【讨论】:

  • 这对我有用。我有一个自定义 UICollectionViewCell,我在 layoutSubviews 中进行格式化。有人知道为什么这个解决方案有效吗?
  • @STANGMMX,A'sa Dickens 的回答解释了原因。
【解决方案6】:

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

【讨论】:

  • 谢谢。它对我有帮助。我昨天遇到了这个问题(在 iOS 7 上)。它对 iOS 7 有帮助。
  • @MaciejSwic 在顶部看到我的答案。
  • 这对我有用!将 iOS 7.1 与 Swift 一起使用。我正在删除并添加对 viewDidLayoutSubviews 的约束。我删除了超级调用,但它仍然无法正常工作,但这个解决方案成功了!给这只恐龙一片叶子! :)
  • 使用 iOS 7.1 也为我工作!
【解决方案7】:

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

【讨论】:

  • 完美洞察!我需要很长时间才能意识到这一点,特别是因为如果我使用禁用了 AutoLayout 的 UIView,我的应用程序不会崩溃。
  • 超级!另请参阅下面的@Arnaud 回复
【解决方案8】:

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

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

【讨论】:

  • 我也是这样做的。不过,如果您想使用自动布局,这并不是一个真正的解决方案
【解决方案9】:

我有类似的问题不是在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 上的工作方式不同。

【讨论】:

  • 伴侣,你只是拯救我的一天!
【解决方案10】:

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

&lt;view contentMode="scaleToFill" horizontalHuggingPriority="1000" id="1" translatesAutoresizingMaskIntoConstraints="YES" customClass="MXWCollapsibleTableHeaderView"&gt;

【讨论】:

    【解决方案11】:

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

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

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

    【讨论】:

      【解决方案12】:

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

      [self addSubview:someView];

      你必须使用

      [self.contentView addSubview:someView];

      【讨论】:

        【解决方案13】:

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

        【讨论】:

          【解决方案14】:

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

          【讨论】:

            【解决方案15】:

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

            【讨论】:

              【解决方案16】:

              我没有为这个问题找到任何合适的解决方案,但您可以通过使用框架来修复它,而不是将 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];
              

              【讨论】:

                【解决方案17】:

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

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

                【讨论】:

                  【解决方案18】:

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

                  self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
                  

                  默认设置为 UIViewAutoresizingNone

                  【讨论】:

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

                  就我而言,

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

                  self.tableView.backgroundView = self.tableBackgroundImageView;
                  

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

                  然后修复。

                  【讨论】:

                    【解决方案20】:

                    我找到了解决办法。

                    在我的例子中,我在故事板中创建了单元格的视图(启用了自动布局),并在我的 ViewController.m 中定义了自定义 UITableViewCell 界面,我必须将界面移动到 ViewController.h。

                    【讨论】:

                      【解决方案21】:

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

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

                      解决方案

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

                      提案

                      你不应该使用 UITableViewCell 的原生元素并改变 它。

                      【讨论】:

                        【解决方案22】:

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

                        【讨论】:

                          【解决方案23】:

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

                          【讨论】:

                            【解决方案24】:

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

                            【讨论】:

                              【解决方案25】:

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

                              【讨论】:

                                【解决方案26】:

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

                                【讨论】:

                                  【解决方案27】:

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

                                  Check out

                                  出现在 iOS

                                  【讨论】:

                                    【解决方案28】:

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

                                    - (void)layoutSubviews
                                    {
                                    
                                        [self _updateConstraints];
                                    
                                        [super layoutSubviews];
                                    }
                                    

                                    【讨论】:

                                      【解决方案29】:

                                      我修改了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"
                                      

                                      【讨论】:

                                        【解决方案30】:

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

                                        【讨论】:

                                          猜你喜欢
                                          • 2015-07-09
                                          • 2014-10-23
                                          • 2015-11-10
                                          • 2013-07-28
                                          • 2013-11-19
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          相关资源
                                          最近更新 更多