“Tata Letak Otomatis masih diperlukan setelah menjalankan -layoutSubviews” dengan subclass UITableViewCell


115

Menggunakan XCode 4.5 dan iOS 6, saya mengembangkan aplikasi dengan tampilan tabel sederhana dengan sel khusus. Saya telah melakukan ini ratusan kali di iOS 5 dan di bawahnya, tetapi untuk beberapa alasan sistem autoLayout baru memberi saya banyak masalah.

Saya mengatur tampilan tabel dan sel prototipe saya di IB, menambahkan subview dan menghubungkannya sebagai IBOutlets kemudian mengatur delegasi dan dataSource saya. Namun sekarang setiap kali sel pertama diambil cellForRowAtIndexPath, saya mendapatkan kesalahan berikut:

*** Kegagalan pernyataan di - [ShopCell layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

*** Menghentikan aplikasi karena pengecualian yang tidak tertangkap 'NSInternalInconsistencyException', alasan: 'Tata Letak Otomatis masih diperlukan setelah menjalankan -layoutSubviews. Implementasi -layoutSubviews dari ShopCell perlu memanggil super. '

Saya belum mengimplementasikan metode -layoutSubviews di sel subclass saya (ShopCell), dan bahkan ketika saya mencoba melakukan itu dan menambahkan panggilan super seperti yang disarankan saya masih mendapatkan kesalahan yang sama. Jika saya menghapus subview dari sel di IB, dan mengubahnya menjadi UITableViewCell standar, semuanya bekerja seperti yang diharapkan, meskipun tentu saja saya tidak memiliki data di sel saya.

Saya hampir yakin bahwa ada sesuatu yang sederhana yang saya lewatkan, tetapi tidak dapat menemukan dokumentasi atau panduan untuk menyarankan kesalahan saya. Bantuan apa pun akan dihargai.

Edit: Baru saja mencoba mengubahnya menjadi UITableViewCell di IB dan membiarkan semua subview di tempatnya, masih kesalahan yang sama.


Coba lldb [[UIWindow keyWindow] _autoLayoutTrace]di area debugger jika tata letak otomatis digunakan.
A-Live

3
Apakah Anda menggunakan UIView untuk sel khusus, bukan UITableViewCell? Saya memiliki masalah yang sama. Saya memiliki UIView untuk sel khusus dan menambahkan sub tampilan untuk itu. Berubah menjadi UITableViewCell dan berhasil.

Hai mike, bagaimana Anda mendefinisikan outlet? Apakah mereka properti dalam file implementasi Anda dalam ekstensi kelas?
kocodude

@ A-Live Setiap kali saya mencoba menggunakan metode itu, saya mendapatkan kesalahan di debugger .... apakah metode ini masih valid? Sunting: Tidak masalah, itu adalah huruf kecil l di autolayout.
borrrden

hapus centang pada kotak autoLayout di inspector lalu bersihkan dan jalankan. itu akan berhasil.
Nico

Jawaban:


57

Saya mengalami masalah yang sama saat menambahkan batasan dalam kode secara manual. Dalam kode, saya melakukan hal berikut:

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

Hipotesa

Dari apa yang saya tahu, masalahnya adalah ketika Anda menonaktifkan translatesAutoresizingMaskIntoConstraints, UITableViewCell mulai menggunakan Tata Letak Otomatis dan secara alami gagal karena implementasi yang mendasari layoutSublayersForLayertidak memanggil super. Seseorang dengan Hopper atau alat lain dapat mengonfirmasi ini. Karena Anda menggunakan IB, Anda mungkin bertanya-tanya mengapa ini menjadi masalah ... dan itu karena menggunakan IB secara otomatis menonaktifkan translatesAutoresizingMaskIntoConstraintstampilan yang menambahkan batasan (secara otomatis akan menambahkan batasan lebar dan tinggi di tempatnya).

Larutan

Solusi saya adalah memindahkan semuanya ke contentView.

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

Saya tidak 100% yakin apakah ini akan bekerja di Interface Builder, tetapi jika Anda mendorong semuanya keluar dari sel Anda (dengan asumsi bahwa Anda memiliki sesuatu secara langsung di dalamnya) maka itu akan berfungsi. Semoga ini bisa membantu Anda!


4
Saya juga perlu menambahkan subview.translatesAutoresizingMaskIntoConstraints = NO'pada setiap subview yang saya tambahkan ke contentView.
Jay Peyer

5
Ini berhasil untuk saya. Juga, pastikan Anda tidak menelepon self.contentView.translatesAutoresizingMaskIntoConstraints = NOuntuk UITableViewCell.
Maurizio

53

Rupanya, implementasi layoutSubviews UITableViewCell tidak memanggil super, yang merupakan masalah dengan tata letak otomatis. Saya tertarik untuk melihat apakah menjatuhkan kategori di bawah ini ke dalam proyek memperbaiki banyak hal. Ini membantu dalam proyek uji.

#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

Saya mungkin menambahkan masalah yang muncul saat saya menggunakan backgroundView pada sel tabel, karena hal itu akan ditambahkan sebagai subview ke sel (sedangkan sebagian besar subview harus ditambahkan ke contentView sel tabel, yang biasanya berfungsi lebih baik).

Catatan: Tampaknya bug ini diperbaiki di iOS7; Saya dapat menghapus kode ini, atau setidaknya menambahkan pemeriksaan runtime sehingga hanya dilakukan jika berjalan di iOS6.


Hal yang aneh adalah bahwa ini berfungsi dengan baik dengan UITableViewCell biasa untuk saya, hanya saja tidak untuk subkelas ...
borrrden

Anda akan berpikir seperti itu, tetapi yang saya miliki hanyalah metode init, tidak ada yang lain> <. Saya tidak pernah mengganti layoutSubviews dalam hidup saya haha. Saya pikir masalahnya adalah tampilan khusus yang digunakan UITableViewCell sebagai tampilan akarnya tidak dapat menggunakan tata letak otomatis karena menggantikan layoutSubviews (jadi ketika Anda mencoba menambahkan batasan ke tampilan root, itu akan gagal)
borrrden

6
Saya harus membuat kategori seperti itu UITableViewuntuk alasan yang sama (iOS 6.1 b1)
Joshua J.McKinnon

5
Apakah ada perbaikan serupa untuk TableHeaderView karena masalahnya masih ada di ios 7?
Softlion

1
Ini bekerja dengan baik. Saya mengalami masalah ini saat mencoba memusatkan subview UIVIew di UITableView. Bahkan di iOS 7, pernyataan itu terjadi. Tetapi itu tidak terjadi di iOS 8, jadi mereka pasti telah mengatasi bug tersebut.
Jordan H

33

Saya memiliki bug yang sama selama beberapa bulan. Tapi saya menemukan apa masalahnya.

Ketika saya membuat file IB, a UIViewsudah ditambahkan. Jika Anda menggunakan tampilan ini, aplikasi tidak mogok saat tata letak otomatis dinonaktifkan (tetapi ada masalah lain). Bila Anda menggunakan tata letak otomatis, Anda harus memilih yang tepat tampilan di perpustakaan objek: UITableViewCell.

Bahkan, Anda harus selalu menggunakan item ini karena semua subviews ditambahkan ke contentViewsatu UITableViewCell.

Itu saja. Semuanya akan baik-baik saja.


Ini seharusnya bukan jawaban yang diterima karena pertanyaannya bukan tentang implementasi menggunakan IB, dan karena masalah ini bisa terjadi ketika Anda tidak menggunakan IB. Jika Anda melakukan pandangan Anda secara terprogram, jawaban @ PhilLoden lebih layak.
Eric

Saya tidak mengerti jawabannya. dapatkah seseorang menjelaskan dengan lebih jelas? terima kasih
hasan

Saya pikir saya punya hak itu. apakah cukup untuk memeriksa kelas att. di inspektur identitas di pembuat antarmuka? atau yang telah ditambahkan adalah tipe lain dan kelas att. telah diperbarui nanti? apakah itu juga menyebabkan masalah?
hasan

@ hasan83 Anda sebenarnya dapat mengembalikan sel. UITableViewCell pada dasarnya adalah UIView dengan pengenal penggunaan kembali.
Arnaud

17

Saya mengalami masalah yang sama dengan custom UITableViewHeaderFooterView+ xib.

Saya melihat beberapa jawaban di sini, tetapi saya menemukan implementasi apa -layoutSubviewsdalam masalah perbaikan kelas tampilan footer kustom saya:

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

1
Berhati-hatilah karena hal ini dapat mengakibatkan loop tanpa akhir dan akhirnya EXC_BAD_ACCESS KERN_PROTECTION_FAILURE
mbi

15

Saya melihat ini sebagai hasil dari memodifikasi batasan dalam implementasi layoutSubviews saya. Memindahkan panggilan ke super dari awal hingga akhir metode memperbaiki masalah.


Ini berhasil untuk saya. Saya memiliki UICollectionViewCell kustom yang saya format di layoutSubviews. Adakah yang tahu mengapa solusi ini berhasil?
STANGMMX

@STANGMMX, jawaban A'sa Dickens menjelaskan alasannya.
Fábio Oliveira

15

Punya masalah yang sama di iOS 7 (iOS 8 sepertinya sudah diperbaiki). Solusi bagi saya adalah menelepon [self.view layoutIfNeeded]di akhir viewDidLayoutSubviewsmetode saya .


Terima kasih. Ini membantu saya, saya bertemu masalah ini kemarin (di iOS 7). ini membantu untuk iOS 7.
Alexander

@MaciejSwic lihat jawaban saya di atas.
Sound Blaster

Ini berhasil untuk saya! Menggunakan iOS 7.1 dengan Swift. Saya menghapus dan menambahkan batasan pada viewDidLayoutSubviews. Saya menghapus panggilan super dan masih tidak berfungsi, tetapi solusi ini berhasil! beri dinosaurus ini daun! :)
jomafer

Bekerja untuk saya juga menggunakan iOS 7.1!
fdlr

14

Saya memiliki masalah yang sama. Masalahnya ada pada cara saya membuat sel Xib. Saya membuat Xib seperti biasa dan baru saja mengubah jenis default "UIView" ke kelas UITableViewCell kustom saya. Cara yang benar adalah dengan terlebih dahulu menghapus tampilan default dan kemudian menyeret objek sel tampilan tabel ke xib. Detail lebih lanjut di sini: http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/


1
Wawasan yang sempurna! Saya membutuhkan waktu lama untuk menyadarinya, terutama karena aplikasi saya tidak akan mogok jika saya menggunakan UIView dengan AutoLayout dinonaktifkan.
Guilherme

Super! lihat juga @Arnaud respone di bawah
Lubbo

7

Saya menyelesaikan masalah ini dengan mematikan "Autolayout" untuk semua subview dari Tabel Tampilan Sel kustom saya.

Di xib untuk sel khusus, pilih subview dan hapus centang File Inspector> Interface Builder Document> Use Autolayout


4
Saya melakukan hal yang sama. Bukan solusi yang sebenarnya jika Anda ingin menggunakan autolayout sekalipun
ajmccall

7

Saya memiliki masalah yang sama bukan pada, UITableViewCellmelainkan pada UITableViewdirinya sendiri. Karena ini hasil pertama di Google saya akan posting disini. Ternyata itulah viewForHeaderInSectionmasalahnya. Saya membuat UITableViewHeaderFooterViewdan mengatur translatesAutoresizingMaskIntoConstraintske NO. Sekarang inilah bagian yang menarik:

IOS 7:

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

Jika saya melakukan ini, aplikasi macet

Tata Letak Otomatis masih diperlukan setelah menjalankan -layoutSubviews. Implementasi -layoutSubviews UITableView perlu memanggil super.

Oke, saya pikir Anda tidak dapat menggunakan tata letak otomatis pada tajuk tampilan tabel dan hanya pada sub-tampilan. Tapi itu tidak sepenuhnya benar seperti yang Anda lihat nanti. Kesimpulannya: Jangan nonaktifkan masker pengubah ukuran otomatis untuk header di iOS 7. Jika tidak, ini berfungsi dengan baik.

iOS 8:

// you have to do this, otherwise you get an auto layout error
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

Jika saya tidak akan menggunakan ini, saya akan mendapatkan output berikut:

Tidak dapat memenuhi batasan secara bersamaan.

Untuk iOS 8 Anda harus menonaktifkan topeng pengubah ukuran otomatis untuk header.

Tidak tahu mengapa itu berperilaku seperti ini tetapi tampaknya Apple memang memperbaiki beberapa hal di iOS 8 dan tata letak otomatis berfungsi secara berbeda di iOS 7 dan iOS 8.


Sobat, simpan saja hariku!
Marcin Małysz

5

Seperti yang telah dinyatakan seseorang di atas, saat Anda membuat tampilan untuk digunakan dalam UITableView, Anda harus menghapus tampilan yang dibuat secara default dan menyeret UITableViewCell atau UITableViewHeaderFooterView sebagai tampilan root. Namun, ada cara untuk memperbaiki XIB jika Anda melewatkan bagian itu. Anda harus membuka file XIB di editor teks dan di tag root dan anak langsungnya menambahkan / mengubah atribut translatesAutoresizingMaskIntoConstraintske YES, misalnya

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


2

Saya menghadapi ini dan tampaknya itu terkait dengan subkelas UITableViewCell sebagai sel prototipe yang secara khusus memiliki subkelas UIView khusus lainnya yang ditambahkan ke dalamnya. Saya menekankan 'adat' di sini karena saya telah berhasil dengan sel yang hanya memiliki anak UIKit, tetapi gagal ketika mencoba membangun batasan untuk tampilan yang telah saya buat dipesan lebih dahulu, melemparkan kesalahan yang disebutkan dalam pertanyaan penulis.

Saya harus memisahkan sel saya menjadi ujung independen yang tidak menggunakan AutoLayout.

Mari berharap Apple membereskan kekacauan ini.


2

Tambahkan subview Anda ke contentView sel, bukan ke sel itu sendiri. Jadi, alih-alih:

[self addSubview:someView];

Anda harus menggunakan

[self.contentView addSubview:someView];


1

Saya menemukan yang satu ini karena saya awalnya menambahkan UIView alih-alih UITableViewCell ke file xib.


1

Saya menghilangkan kesalahan ini dengan melepaskan backgroundViewkonektor dari latar belakang UIImageViewdan accessoryViewkonektor dari UIButtonkustomisasi saya . Saya curiga bahwa ini tidak dimaksudkan untuk digunakan dengan cara saya menggunakannya.


1

Saya mengalami masalah ini pertama kali hari ini. Sampai sekarang saya memiliki beberapa pengalaman dalam menggunakan prototipe subclass UITableViewCell tetapi tidak pernah mengalami masalah ini. Apa yang berbeda tentang sel yang saya kerjakan adalah saya memiliki IBOutlet ke -backgroundView yang saya gunakan untuk mewarnai sel. Saya menemukan bahwa jika saya membuat properti baru dan masih menambahkan UIView baru yang memperpanjang rentang seluruh sel, pernyataan ini hilang. Untuk memverifikasi ini penyebabnya, saya kembali melampirkan tampilan ini ke outlet backgroundView dan pernyataan muncul kembali. Sejauh ini, tidak ada masalah lain yang menggunakan AutoLayout dalam prototipe subclass UITableViewCell sejak saya membuat perubahan ini.


1

Saya tidak mendapatkan solusi yang tepat untuk masalah ini tetapi Anda dapat memperbaikinya dengan menggunakan bingkai dan tidak mengatur properti translatesAutoresizingMaskIntoConstraints ke Tidak (secara default ya, jadi jangan setel)

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

Saya telah mengalami hal yang sama. Ternyata jika Anda secara terprogram menambahkan subview dari ShopCell .xib / storyboard Anda, yang menggunakan tata letak otomatis, sebagai subview ke tampilan lain, pengecualian tersebut mungkin akan muncul, bergantung pada bagaimana batasan Anda dikonfigurasi. Dugaan saya adalah bahwa batasan yang dibuat di IB adalah apa yang menciptakan masalah ketika secara terprogram menambahkan tampilan sebagai subview, karena itu kemudian mempertahankan batasan dari viewA -> viewB sementara itu Anda dapat menambahkan viewB sebagai subview dari viewC. Anda mengerti (kalimat itu bahkan membingungkan saya sendiri)?

Dalam situasi saya - karena tampilan yang sangat sederhana yang menyebabkan masalah - saya membuat tampilan secara terprogram dan bukan di IB. Itu menyelesaikannya. Anda dapat mengekstrak tampilan tersebut ke file xib lain dan menonaktifkan tata letak otomatis untuk itu. Saya kira itu akan berhasil.


0

Dalam beberapa situasi, ini menyelesaikan masalah tata letak dengan mudah (bergantung pada tata letak Anda). Di dalam subkelas UITableView Anda, baik dalam awakeFromNib atau init, setel mask autoresizing:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Secara defaut, ini disetel ke UIViewAutoresizingNone


Ini memecahkan masalah yang saya hadapi. Saya menggunakan tata letak otomatis dalam sel tabel yang digabungkan dengan [tableViewCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].heightuntuk mendapatkan ketinggian, yang kemudian saya gunakan heightForRowAtIndexPath.
NathanAldenSr

0

Dalam kasus saya,

UIImageView yang direferensikan untuk tata letak otomatis untuk UITableView ditetapkan ke backgroundView dari UITableView.

self.tableView.backgroundView = self.tableBackgroundImageView;

Jadi, saya menghapus UIImageView for backgroundView dari UIView (tampilan Root) dan mengatur ulang (menghapus) semua referensi tata letak otomatis ke UIImageView tersebut. Saya menempatkan UIImageView itu untuk background di luar dari UIView (tampilan root). Dan kemudian tetapkan ke backgroundView dari UITableView dalam kode.

Kemudian diperbaiki.


0

Saya sudah menemukan solusinya.

Dalam kasus saya, saya membuat tampilan sel di storyboard (dengan tata letak otomatis diaktifkan) dan saya mendefinisikan antarmuka UITableViewCell kustom di ViewController.m saya, saya harus memindahkan antarmuka ke ViewController.h.


0

Saya mengalami masalah yang sama ketika saya menggunakan storyboard untuk membuat UITableViewCell kustom. Untungnya saya menemukan masalahnya, karena saya mengeluarkan accessoryView ([UITableViewCell setAccessoryView:]) ke UIButton yang saya tambahkan ke sel.

Jadi itu terjadi di proyek saya saat dijalankan di iOS6.

Larutan

Saya melepaskan saluran keluar antara accessoryView dan tombol saya yang berisi sel khusus.

Usul

Anda tidak boleh menggunakan elemen asli UITableViewCell dan mengubahnya.


0

Masalah ini bisa disebabkan karena lupa menelepon ke [super viewDidAppear:]dalam viewDidAppear, tapi saya yakin itu bukan satu-satunya penyebab.


0

Saya memiliki masalah yang sama persis. Inilah masalah dengan proyek saya:
Ketika saya bekerja pada Pembuat Antarmuka untuk membuat UITableViewCell kustom, saya menyeret Tampilan alih-alih Sel Tampilan Tabel dari panel koleksi objek di Xcode
sebagai sel tabel kustom.
Jika Anda berada dalam situasi yang sama, berikut solusinya:
Hapus tampilan di pembuat antarmuka, pastikan Anda menyeret Sel Tampilan Tabel dari panel kumpulan objek dan ulangi tampilan sel tabel kustom. Anda dapat menyalin objek di tampilan lama dan menempelkannya ke kanvas untuk Sel Tampilan Tabel baru.


0

Saya memiliki masalah yang sangat mirip dengan tampilan footer tabel yang saya atur di Xcode 6, iOS 7+. Solusinya adalah dalam format file nib. Rupanya itu macet dalam format Xcode 4 atau semacamnya. Mengubah pengaturan file menjadi "opens in: Xcode 6.0" (atau Default, dalam hal ini), langsung memperbaikinya. Menemukan solusinya secara kebetulan: itu membuat saya gila, jadi saya menghapus seluruh file dan membuatnya lagi, jelas dengan pengaturan default. Saya tidak tahu mengapa hanya mengedit file di Xcode terbaru tidak mengubahnya menjadi format Xcode 5+, seperti yang biasanya terjadi.

f


0

Saya pergi memiliki masalah yang sama. Saya pergi ke DetailViewController saya dan mengganti nama pengenalnya menjadi UIView. Itu sebelumnya di UITableView. Itu memperbaiki masalah. Masalah ini tidak harus ada di DetailViewController Anda. Bisa jadi di tempat lain. Coba ganti namanya menjadi pengenal yang dihormati.


0

Saya memiliki masalah serupa dengan sel tampilan tabel statis di IB. Salah satu sel memiliki subview yang memiliki kelas yang salah diubah menjadi subkelas UITextfield. Kompiler tidak memberikan peringatan / kesalahan apapun. Namun pada waktu proses, sistem tidak dapat memuat pengontrol tampilan dengan error yang disebutkan di atas sebagai akibatnya.



0

Solusi: ubah batasan sebelum memanggil tata letak super

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

0

Saya mengubah jawaban Carl Lindberg untuk menimpaUITableView dan itu mulai bekerja untuk saya:

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

Kemudian MyViewController.msaya baru saja mengimpor kategori:

#import "UITableView+AutoLayoutFix.h"

0

Saya menemui masalah yang sama dan akhirnya menemukan alasannya adalah karena saya menambahkan satu kendala ke UITableViewCell, yang seharusnya adalah contentView UITableViewCell . Ketika saya mengubah batasan semuanya berjalan dengan baik!

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.