UITableViewCellサブクラスで「-layoutSubviewsを実行した後も自動レイアウトが必要」


115

XCode 4.5とiOS 6を使用して、カスタムセルを含むシンプルなテーブルビューのアプリを開発しています。私はこれをiOS 5以下で100回行いましたが、何らかの理由で新しい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に変更して、すべてのサブビューをそのままにしてみましたが、それでも同じエラーが発生しました。


lldb [[UIWindow keyWindow] _autoLayoutTrace]自動レイアウトを使用する場合は、デバッガー領域で試してください。
A-Live

3
UITableViewCellの代わりにカスタムセルにUIViewを使用していますか?私も同じ問題を抱えていました。カスタムセルのUIViewがあり、それにサブビューを追加していました。UITableViewCellに変更され、機能しました。

マイクさん、アウトレットをどのように定義していますか?それらはクラス拡張の実装ファイルのプロパティですか?
kocodude 2012年

@ A-Liveそのメソッドを使用しようとすると、デバッガーでエラーが発生します。このメソッドはまだ有効ですか?編集:気にしないでください。自動レイアウトでは小文字のlです。
12

インスペクタのautoLayoutボックスをオフにして、クリーンして実行します。それはうまくいきます。
Nico

回答:


57

コードに制約を手動で追加しているときに同じ問題が発生しました。コードでは、私は次のことをしていました:

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

仮説

私が言えることから、問題は、を無効にするとtranslatesAutoresizingMaskIntoConstraints、UITableViewCellが自動レイアウトの使用を開始し、の基本的な実装がlayoutSublayersForLayerスーパーを呼び出さないために自然に失敗することです。ホッパーまたは他のツールを持っている人がこれを確認できます。IBを使用しているので、なぜこれが問題であるのか不思議に思うかもしれません... IBを使用するとtranslatesAutoresizingMaskIntoConstraints、ビューに制約が追加されて自動的に無効になるためです(その場所に幅と高さの制約が自動的に追加されます)。

解決

私の解決策は、すべてをに移動することでしたcontentView

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

これがInterface Builderで機能するかどうかは100%わかりませんが、セルからすべてのものを押し出すと(何かが直接それにあると仮定して)、機能するはずです。これがお役に立てば幸いです!


4
subview.translatesAutoresizingMaskIntoConstraints = NO'contentView に追加する各サブビューも追加する必要がありました。
Jay Peyerが

5
これでうまくいきました。また、を呼び出さないようにself.contentView.translatesAutoresizingMaskIntoConstraints = NOしてくださいUITableViewCell
マウリツィオ

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で
正常に動作し

あなたはそう思うでしょうが、私が持っているのはinitメソッドだけで、他には何もありません> <。私の人生では、layoutSubviewsをオーバーライドしたことはありません。問題は、UITableViewCellがルートビューとして使用するカスタムビューが自動レイアウトを使用できないためです(レイアウトサブビューをオーバーライドするため、ルートビューに制約を追加しようとすると失敗します)
borrrden

6
UITableView同じ理由でこのようなカテゴリを作成する必要がありました(iOS 6.1 b1)
Joshua J. McKinnon '28

5
問題はまだiOS 7に存在するため、TableHeaderViewに同様の修正はありますか?
Softlion 2014

1
これはうまくいきます。UITableViewでUIVIewサブビューを中央に配置しようとしたときに、この問題が発生しました。iOS 7でもアサーションが発生します。しかし、iOS 8では発生しないので、彼らはバグに対処したに違いありません。
ジョーダンH

33

同じバグが数か月ありました。しかし、私は何が問題であるかを見つけました。

IBファイルを作成すると、a UIViewはすでに追加されています。このビューを使用すると、自動レイアウトが無効になっていてもアプリはクラッシュしません(ただし、他の問題があります)。自動レイアウトを使用する場合は、オブジェクトライブラリで適切なビューを選択する必要がありますUITableViewCell

実際、すべてのサブビューがのに追加されるため、常にこのアイテムを使用する必要contentViewがありUITableViewCellます。

それで全部です。すべて元気です。


質問はIBを使用した実装に関するものではなく、IBを使用していないときにこの問題が発生する可能性があるため、これは受け入れられる答えではありません。プログラムでビューを実行している場合は、@ PhilLodenの答えの方が現実的です。
Eric

答えがわかりませんでした。誰かがより明確に説明できますか?感謝
ハサン

私にはその権利があると思います。クラスattをチェックするだけで十分です。インターフェースビルダーのアイデンティティインスペクターで?または、追加されたは別のタイプとクラスの属性でした。後で更新されましたか?それも問題の原因ですか?
ハサン、2014

@ hasan83実際に細胞を返すことができます。UITableViewCellは基本的に、再利用識別子を持つUIViewです。
Arnaud '19

17

カスタムUITableViewHeaderFooterView+ xibでも同じ問題が発生しました。

ここでいくつかの回答を見ました-layoutSubviewsが、カスタムフッタービュークラスのどの実装が問題を修正しているのかがわかりました。

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

1
これにより無限ループが発生し、最終的にEXC_BAD_ACCESS KERN_PROTECTION_FAILURE
mbi

15

これは、layoutSubviewsの実装で制約を変更した結果として発生しました。メソッドの最初から最後まで呼び出しをsuperに移動すると、問題が解決しました。


これでうまくいきました。私は、layoutSubviewsでフォーマットしているカスタムUICollectionViewCellを持っています。このソリューションが機能する理由を誰かが知っていますか?
STANGMMX 2013

@ STANGMMX、A'sa Dickensの回答がその理由を説明しています。
ファビオ・オリベイラ

15

iOS 7でも同じ問題がありました(iOS 8は修正されているようです)。私の解決策[self.view layoutIfNeeded]は、viewDidLayoutSubviewsメソッドの最後に呼び出すことでした。


ありがとうございました。昨日(iOS 7で)この問題に遭遇しました。iOS 7に役立ちます
Alexander

@MaciejSwic私の答えを上部に表示します。
Sound Blaster 2014

これは私のために働いた!SwiftでiOS 7.1を使用する。viewDidLayoutSubviewsの制約を削除して追加していました。私はスーパーコールを削除しましたが、それでも機能しませんでしたが、この解決策でうまくいきました!この恐竜に葉を与えなさい!:)
jomafer 2015年

私もiOS 7.1を使用して動作しました!
fdlr

14

同じ問題がありました。問題は、セルXibの作成方法にありました。通常のようにXibを作成し、デフォルトの「UIView」のタイプをカスタムUITableViewCellクラスに変更しました。正しい方法は、最初にデフォルトビューを削除してから、テーブルビューのセルオブジェクトをxibにドラッグすることです。詳細はこちら:http : //allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/


1
完璧な洞察!AutoLayoutが無効になっているUIViewを使用してもアプリがクラッシュしないので、私はそれに気付くまでに時間がかかります。
ギルヘルム2013年

素晴らしい!以下の@Arnaud responeも参照してください
Lubbo 2013年

7

カスタムテーブルビューセルのすべてのサブビューの「自動レイアウト」をオフにすることで問題を解決しました。

カスタムセルのxibで、サブビューを選択し、[ファイルインスペクター]> [Interface Builder Document]> [Use Autolayout]をオフにします。


4
私も同じことをしました。自動レイアウトを使用する場合でも、実際には解決策ではありません
ajmccall

7

私には似たような問題がありましたUITableViewCellが、UITableViewそれ自体ではありません。Googleでの最初の結果なのでここに投稿します。それが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では異なる動作をしているようです。


あなたは私の日を救うだけです!
MarcinMałysz2015

5

上記の誰かがすでに述べたように、UITableViewで使用するビューを作成する場合、デフォルトで作成されたビューを削除し、UITableViewCellまたはUITableViewHeaderFooterViewをルートビューとしてドラッグする必要があります。ただし、その部分を見逃した場合に備えて、XIBを修正する方法があります。テキストエディターとルートタグでXIBファイルを開き、その直接の子で属性translatesAutoresizingMaskIntoConstraintsをに追加/変更する必要があります。YES次に例を示します。

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


2

私はこれに遭遇し、他のカスタムUIViewサブクラスが追加されたプロトタイプセルとして、UITableViewCellサブクラスに関連しているようです。UIKitの子を持つセルで成功したので、ここで「カスタム」を強調しますが、カスタムメイドで作成したビューの制約を構築しようとすると失敗し、著者の質問に記載されたエラーがスローされます。

AutoLayoutを使用しない独立したペン先に細胞を分離する必要がありました。

Appleがこの混乱を片付けることを期待しましょう。


2

セル自体ではなく、セルのcontentViewにサブビューを追加します。だから代わりに:

[self addSubview:someView];

あなたは使わなければならない

[self.contentView addSubview:someView];


1

最初にUITableViewCellではなくUIViewをxibファイルに追加したため、この問題が発生しました。


1

私は切り離すことによって、このエラーを排除しbackgroundView、私のバックグラウンドからコネクターをUIImageViewし、accessoryView私からのコネクタUIButtonカスタマイゼーション。私はそれらが私がそれらを使用していた方法で使用されることを意図されていなかったと思います。


1

今日、初めてこの問題に遭遇しました。これまで、プロトタイプUITableViewCellサブクラスを使用していくつかの経験がありましたが、この問題に遭遇したことはありません。私が使用していたセルの違いは、セルの色付けに使用していた-backgroundViewへのIBOutletがあったことです。新しいプロパティを作成し、セル全体のスパンを拡張する新しいUIViewを追加した場合、このアサーションは解消されました。これが原因であることを確認するために、このビューをbackgroundViewアウトレットにアタッチすることに戻り、アサーションが再表示されました。これまでのところ、この変更を行ったので、サブクラス化されたプロトタイプUITableViewCellでAutoLayoutを使用する他の問題はありません。


1

この問題の適切な解決策はありませんでしたが、フレームを使用し、translatesAutoresizingMaskIntoConstraintsプロパティをNoに設定しないことで修正できます(デフォルトでは、yesなので設定しないでください)。

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で作成された制約は、ビューをサブビューとしてプログラムで追加するときに問題を引き起こすものだと考えられます。分かりましたか(その文は私を混乱させるほどです)?

私の状況では、問題を引き起こしたのは非常に単純なビューだったので、IBではなくプログラムでビューを作成しました。それで解決しました。これらのビューを他のxibファイルに抽出し、それらの自動レイアウトを無効にすることができます。私はそれがうまくいくと思います。


0

状況によっては、これによりレイアウトの問題が簡単に解決されます(レイアウトによって異なります)。UITableViewサブクラス内で、awakeFromNibまたはinitのいずれかで、自動サイズ変更マスクを設定します。

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

デフォルトでは、UIViewAutoresizingNoneに設定されています。


これは私が直面していた問題を解決しました。テーブルセル内で自動レイアウトを使用し[tableViewCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].heightて高さを取得し、それをで使用していheightForRowAtIndexPathます。
NathanAldenSr 2013

0

私の場合、

UITableViewの自動レイアウトで参照されるUIImageViewは、UITableViewのbackgroundViewに割り当てられます。

self.tableView.backgroundView = self.tableBackgroundImageView;

したがって、私はbackgroundViewのUIImageViewをUIView(ルートビュー)から削除し、そのUIImageViewへのすべての自動レイアウト参照をリセット(削除)しました。背景用のUIImageViewをUIView(ルートビュー)の外側に配置しました。次に、コードでUITableViewのbackgroundViewに割り当てます。

次に修正しました。


0

私は解決策を見つけました。

私の場合、ストーリーボードでセルのビューを作成し(自動レイアウトを有効にして)、ViewController.mでカスタムUITableViewCellインターフェイスを定義しました。インターフェイスをViewController.hに移動する必要があります。


0

ストーリーボードを使用してカスタムUITableViewCellを作成すると、同じ問題が発生しました。幸い、私が問題を見つけたのは、セルに追加したUIButtonにAccessoryView([UITableViewCell setAccessoryView:])をアウトレットしたためです。

そのため、iOS6で実行したときに私のプロジェクトで発生しました。

解決

カスタムセルが含まれていた私のアクセサリボタンとボタンの間のアウトレットを解放します。

提案

UITableViewCellのネイティブ要素を使用して変更しないでください。


0

この問題は、[super viewDidAppear:]viewDidAppearでの呼び出しを忘れたことが原因で発生する可能性がありますが、それが唯一の原因ではないと確信しています。


0

私はまったく同じ問題を抱えていました。ここに私のプロジェクトの問題があります。
インターフェイスビルダーでカスタムUITableViewCellを作成したときに、Xcodeのオブジェクトコレクションペインからテーブルビューセルではなくビューを カスタムテーブルセルとしてドラッグしました。 同じ状況の場合の解決策は次のとおりです。 インターフェイスビルダーでビューを削除し、オブジェクトコレクションペインからテーブルビューセルをドラッグして、カスタムテーブルセルビューをやり直してください。古いビューのオブジェクトをコピーして、新しいテーブルビューセルのキャンバスに貼り付けることができます。



0

Xcode 6、iOS 7以降で設定していたテーブルフッタービューで、非常によく似た問題が発生しました。解決策はnibファイルの形式でした。どうやらそれはXcode 4形式か何かで動かなくなっていました。ファイル設定を「opens in:Xcode 6.0」(または、それに関してはデフォルト)に変更すると、即座に修正されました。偶然に解決策を見つけました。それは私を夢中にさせていたので、ファイル全体を削除して、デフォルトの設定で明らかに作成し直しました。最新のXcodeでファイルを編集しただけでは、Xcode 5+形式に変換されなかった理由がよくわかりません。

f


0

私は同じ問題を持って行ってきました。私はDetailViewControllerに行き、識別子の名前をUIViewに変更しました。以前はUITableViewにありました。問題を修正しました。この問題は、DetailViewControllerにある必要はありません。それは他のどれでもありえます。尊敬する識別子に名前を変更してみてください。


0

IBの静的テーブルビューセルでも同様の問題がありました。セルの1つに、誤ってUITextfieldのサブクラスに変更されたクラスを持つサブビューがありました。コンパイラーは警告/エラーを出しませんでした。しかし、実行時に、システムは前述のクラッシュによりビューコントローラーをロードできませんでした。



0

解決策:スーパーレイアウトを呼び出す前に制約を変更する

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

0

代わりに、カールリンドバーグの回答を変更してオーバーライド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のcontentViewである必要がある1つの制約をUITableViewCellに追加したこと原因であることがわかりまし。制約を変更すると、すべてがうまくいきました!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.