web-dev-qa-db-ja.com

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

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に変更して、すべてのサブビューをそのままにしてみましたが、同じエラーが発生しました。

115
Mike Mayo

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

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

仮説

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

ソリューション

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

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

Interface Builderでこれが機能するかどうかは100%確信はありませんが、セルからすべてをプッシュすると(セルに直接何かがあると仮定して)動作するはずです。これがあなたを助けることを願っています!

57
Malaxeur

どうやら、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で実行している場合にのみ実行されるようにすることができました。

53
Carl Lindberg

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

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

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

それで全部です。すべてうまくいきます。

33
Arnaud

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

私はここでいくつかの答えを見ましたが、カスタムフッタービュークラスのどの実装-layoutSubviewsが問題を修正したかを見つけました:

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

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

15
Keller

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

15
Phil Loden

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

14
Trunal Bhanse

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

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

7
Johno

UITableViewCellではなくUITableView自体にも同様の問題がありました。 Googleでの最初の結果であるため、ここに投稿します。 viewForHeaderInSectionが問題であることが判明しました。 UITableViewHeaderFooterViewを作成し、translatesAutoresizingMaskIntoConstraintsNOに設定しました。ここからが興味深い部分です。

iOS 7:

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

これを行うと、アプリがクラッシュします

-layoutSubviewsの実行後も自動レイアウトが必要です。 UITableViewの-layoutSubviewsの実装は、superを呼び出す必要があります。

OK、テーブルビューヘッダーでは自動レイアウトを使用できず、サブビューでのみ使用できると思いました。しかし、後で見るようにそれは完全な真実ではありません。 要約すると: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で異なる動作をするようです。

7
testing

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

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

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

[self addSubview:someView];

あなたは使わなければなりません

[self.contentView addSubview:someView];

2

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

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

Appleがこの混乱を一掃することを期待しましょう。

2
Lee Probert

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

1
mjmdavis

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

1
Eric Schramm

この問題の適切な解決策はありませんでしたが、framesを使用し、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];
1
sanjana

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

1
Owen Godfrey

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

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

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"
0
plowman

私は同じ問題に出会い、最終的に理由を見つけました。UITableViewCellに1つの制約を追加したことです。これはUITableViewCellのcontentViewでなければなりません。制約を変更すると、すべてがうまくいきました!

0
Alfy

ストーリーボードを使用してカスタムUITableViewCellを作成すると、同じ問題が発生しました。幸いなことに、アクセサリビュー([UITableViewCell setAccessoryView:])をセルに追加したUIButtonにアウトレットしたため、問題が見つかりました。

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

ソリューション

AccessoriesViewとカスタムセルを含むボタンの間のアウトレットを解放します。

提案

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

0
Wanqiang Ji

問題は、サブビューへのレイアウト呼び出しの順序付けです:

チェックアウト

iOS <8に表示されます

0
Shanu ji

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

f

0
user3099609

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

0
Yannick Winters

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

0
RandomDude

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

0
us_david

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

0
michaelsnowden

私は同じことを経験しています。 ShopCell .xib/storyboardからサブビューをプログラムで追加し、自動レイアウトを別のビューのサブビューとして使用すると、制約の構成方法によっては例外がスローされることが判明しました。私の推測では、IBで作成された制約が、ビューをサブビューとしてプログラムで追加するときに問題を引き起こすものであると考えられます。あなたはそれを得ました(その文は自分自身を混乱させることさえあります)?

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

0
Kasper Munck

解決策:スーパーlayoutSubviewsを呼び出す前に制約を変更します

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}
0
abuharsky

私の場合、

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

self.tableView.backgroundView = self.tableBackgroundImageView;

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

その後修正。

0
Conan Kim

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

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

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

0
Arie Litovsky