"Автоматичний макет все ще потрібен після виконання -layoutSubviews" з підкласом UITableViewCell


115

Використовуючи XCode 4.5 та iOS 6, я розробляю додаток із простим поданням таблиці із спеціальними клітинками. Я робив це сто разів у iOS 5 і нижче, але чомусь нова система автоматичного компонування доставляє мені багато проблем.

Я налаштував свій огляд таблиці та прототип комірки в IB, додав підпогляди та з'єднав їх як IBOutlets, а потім налаштував мій делегат та dataSource. Однак тепер, коли перша комірка отримана cellForRowAtIndexPath, я отримую таку помилку:

*** Невдача ствердження в - [ShopCell layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

*** Закінчення програми через невиконаний виняток "NSInternalInconsistencyException", причина: "Автоматична розмітка все-таки потрібна після виконання -layoutSubviews. Реалізація ShopCell -layoutSubviews потребує виклику super. '

Я не реалізував метод -layoutSubviews у своїй підкласовій комірці (ShopCell), і навіть коли я намагаюся це зробити і додаю супервиклик, як це підказує, я все одно отримую ту саму помилку. Якщо я видаляю підвід з осередку в IB і замінюю його на стандартний UITableViewCell, все працює так, як очікувалося, хоча, звичайно, я не маю даних у своїх клітинах.

Я майже впевнений, що чогось простого мені не вистачає, але не можу знайти жодної документації чи посібників, які б підказували, що я зробив не так. Будь-яка допомога буде вдячна.

Редагування: Просто спробували змінити його на UITableViewCell у IB та залишити всі підпогляди на місці, як і раніше однакова помилка.


Спробуйте lldb [[UIWindow keyWindow] _autoLayoutTrace]в області налагодження, якщо використовується автоматичне розташування.
A-Live

3
Ви використовуєте UIView для користувацької комірки замість UITableViewCell? У мене була така ж проблема. У мене був UIView для користувацької комірки і додав до неї підпрограми. Змінено на UITableViewCell і воно спрацювало.

Гей, Майку, як ти визначаєш торгові точки? Чи є вони властивостями у вашому файлі реалізації у розширенні класу?
kocodude

@ A-Live Щоразу, коли я намагаюся використовувати цей метод, я отримую помилку в налагоджувачі .... чи цей метод все-таки діє? Редагувати: Ніколи не пам’ятайте, що це мале літер в автоматичному розкладі.
borrrden

зніміть прапорець у автоматичному розкладі в інспекторі, потім очистіть і запустіть. це буде потворно працювати.
Ніко

Відповіді:


57

Я зіткнувся з тією ж проблемою під час додавання обмежень у код вручну. У коді я робив наступне:

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

Гіпотеза

З того, що я можу сказати, проблема полягає в тому, що при відключенні translatesAutoresizingMaskIntoConstraintsUITableViewCell починає використовувати автоматичний макет і, природно, не працює, оскільки основна реалізація layoutSublayersForLayerне викликає супер. Хтось із 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.
Мауріціо

53

Мабуть, реалізація layoutUubviews UITableViewCell не викликає супер, що є проблемою з автоматичним компонуванням. Мені буде цікаво побачити, чи виправлення нижчезазначеної категорії у проектах виправляє речі. Це допомогло в тестовому проекті.

#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

Ви б могли подумати про це, але все, що я маю - це метод init, більше нічого> <. У житті я ніколи не перекривляв макетSubviews. Я думаю, що проблема полягає в користувацькому представленні, яке UITableViewCell використовує як свій корінний вигляд, не може використовувати автоматичний макет, оскільки він переосмислює layoutSubviews (тому, коли ви намагаєтеся додати обмеження до кореневого виду, він не вийде)
borrrden

6
Мені довелося створити таку категорію з UITableViewтієї ж причини (iOS 6.1 b1)
Джошуа Дж. МакКіннон

5
Чи існує подібне виправлення для TableHeaderView, оскільки проблема все ще існує в ios 7?
Softlion

1
Це чудово працює. З цією проблемою я зіткнувся, коли я намагався зосередити підвідвід UIVIew в UITableView. Навіть в iOS 7 відбувається твердження. Але це не відбувається в iOS 8, тому вони, мабуть, вирішили помилку.
Йорданія H

33

У мене була однакова помилка кілька місяців. Але я виявив, в чому проблема.

Коли я створюю IB-файл, a UIViewвже додається. Якщо ви користуєтеся цим поданням, додаток не виходить з ладу, коли вимкнено автоматичний макет (але є й інші проблеми). При використанні автоматичної компонування, ви повинні вибрати правильний вид в бібліотеці об'єктів: UITableViewCell.

Насправді, ви повинні завжди використовувати цей пункт , тому що все підвиди додають до contentViewз UITableViewCell.

Це все. Все буде добре.


Це не повинно бути прийнятою відповіддю, оскільки питання не про реалізацію з використанням ІБ, а тому, що ця проблема може статися, коли ви не використовуєте ІБ. Якщо ви робите свої погляди програмно, відповідь @ PhilLoden є більш життєздатною.
Ерік

Я не зрозумів відповіді. хтось може пояснити більш чітко? дякую
hasan

Я думаю, що я маю на це право. чи достатньо перевірити клас att. у інспектора ідентичності в програмі інтерфейсів? або додане було іншого типу та класу att. оновлено пізніше? це також викликає проблеми?
хасан

@ hasan83 Ви можете фактично повернути клітинку. UITableViewCell - це в основному UIView з ідентифікатором повторного використання.
Арно

17

У мене були такі ж проблеми з custom UITableViewHeaderFooterView+ xib.

Тут я побачив кілька відповідей, але знайшов, яка реалізація -layoutSubviewsв моїй проблемі з виправленнями класу подання нижнього колонтитулу:

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

1
Будьте уважні,
mbi

15

Я бачив це як результат зміни обмежень у моїй реалізації layoutSubviews. Переміщення виклику в супер від початку до кінця методу вирішило проблему.


Це працювало для мене. У мене є власний UICollectionViewCell, який я форматую в layoutSubviews. Хтось знає, чому це рішення працює, хоча?
STANGMMX

@STANGMMX, відповідь Аси Діккенс пояснює, чому.
Фабіо Олівейра

15

У iOS 7 була така ж проблема (iOS 8, здається, виправляється). Рішенням для мене було зателефонувати [self.view layoutIfNeeded]наприкінці мого viewDidLayoutSubviewsметоду.


Дякую. Це допомагає мені. Я зіткнувся з цією проблемою вчора (на iOS 7). це допомагає для iOS 7.
Олександр

@MaciejSwic дивіться мою відповідь вгорі.
Sound Blaster

Це працювало для мене! Використання iOS 7.1 з Swift. Я видаляв і додавав обмеження на viewDidLayoutSubviews. Я видалив супер дзвінок, і він все ще не працював, але це рішення зробило свою справу дайте цьому динозавру лист! :)
jomafer

Для мене теж працював за допомогою iOS 7.1!
fdlr

14

У мене було те саме питання. Проблема полягала в тому, що я створював клітинку Xib. Я створив Xib як звичайний і просто змінив тип за замовчуванням "UIView" на свій спеціальний клас UITableViewCell. Правильний спосіб - спочатку видалити подання за замовчуванням, а потім перетягнути об'єкт комірки подання таблиці на xib. Детальніше тут: http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/


1
Ідеальне розуміння! Я б зайняв віки, щоб зрозуміти це, спеціально тому, що мої програми не виходять з ладу, якщо я користувачу UIView з вимкненою функцією AutoLayout.
Гільгерме

Супер! дивіться також @Arnaud відповідь нижче
Lubbo

7

Я вирішив проблему, вимкнувши "Автоматичний розклад" для всіх підпрезентацій моєї користувальницької комірки таблиці.

У xib для користувацької комірки виберіть підвідмову та зніміть прапорець File Inspector> Document 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.


Мате, ти просто врятуй мені день!
Marcin Małysz

5

Як уже було зазначено вище, коли ви створюєте представлення для використання в UITableView, ви повинні видалити представлення, створене за замовчуванням, і перетягнути UITableViewCell або UITableViewHeaderFooterView як кореневий вигляд. Однак є спосіб виправити XIB у випадку, якщо ви пропустили цю частину. Ви повинні відкрити файл XIB в текстовому редакторі і в кореневому тезі і його прямий нащадок додати / змінити атрибут translatesAutoresizingMaskIntoConstraintsдо YES, наприклад ,

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


2

Я зіткнувся з цим, і, здається, він пов'язаний з підкласами UITableViewCell як клітинами-прототипами, які спеціально мають до них додані інші користувацькі підкласи UIView. Я наголошую на "звичаї" тут, тому що я мав успіх у клітинках, у яких просто є діти UIKit, але він падає, коли намагаються створити обмеження для створених мною поглядів, видаючи помилку, заявлену у питанні авторів.

Мені довелося відокремлювати клітинки на незалежні гібриди, які не використовують функцію AutoLayout.

Будемо сподіватися, що Apple очистить цей безлад.


2

Додайте свої підпогляди до contentView комірки замість самої комірки. Тож замість:

[self addSubview:someView];

ви повинні використовувати

[self.contentView addSubview:someView];


1

Я стикався з цим, тому що я спочатку додав UIView замість UITableViewCell до файлу xib.


1

Я усунув цю помилку, від'єднавши backgroundViewроз'єм від мого фону UIImageViewта accessoryViewроз'єм від моїх UIButtonналаштувань. Я підозрюю, що вони не мали бути використані так, як я ними користувався.


1

Я сьогодні вперше зіткнувся з цим питанням. До цього часу я мав деякий різноманітний досвід використання прототипу підкласів UITableViewCell, але жодного разу не стикався з цією проблемою. Що стосується комірки, з якою я працював, це було те, що у мене був IBOutlet до -backgroundView, який я використовував для фарбування комірки. Я виявив, що якщо я створив нову властивість і все-таки додав свіжий UIView, який розтягнув проміжок всієї комірки, це твердження відійшло. Щоб переконатися, що це було причиною, я повернувся до приєднання цього виду до розетки backgroundView, і твердження знову з’явилося. Поки жодних інших проблем із використанням AutoLayout в підкласовому прототипі 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 / раскадровки, який використовує автоматичний макет, як підвід до іншого перегляду, цей виняток може бути перекинуто, залежно від налаштування ваших обмежень. Я гадаю, що обмеження, створені в ІБ, створюють проблеми, коли програмно додається подання як підпогляд, оскільки це тоді підтримує обмеження з viewA -> viewB, тим часом ви можете додати viewB як підпогляд viewC. Ви це зрозуміли (це речення мене навіть бентежить)?

У моїй ситуації - оскільки це викликало проблему - дуже прості погляди - я створював погляди програмно, а не в ІБ. Це вирішило це. Ви можете витягнути ці представлення в інші файли xib і відключити автоматичну компоновку для них. Я думаю, це спрацювало б.


0

У деяких ситуаціях це вирішує проблему компонування легко (залежно від вашого макета). Всередині підкласу UITableView або в awakeFromNib, або init встановіть маску автоматичної зміни:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

За умовчанням він встановлюється на UIViewAutoresizingNone


Це вирішило проблему, з якою я стикався. Я використовую автоматичне розташування в комірці таблиці в поєднанні з, [tableViewCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].heightщоб отримати висоту, яку я потім використовую heightForRowAtIndexPath.
NathanAldenSr

0

У моєму випадку

Посилання UIImageView для автоматичного макета для UITableView призначається backgroundView UITableView.

self.tableView.backgroundView = self.tableBackgroundImageView;

Отже, я видалив UIImageView для backgroundView з UIView (Root view) і скинув (видалити) всі посилання автоматичного макета на цей UIImageView. Я розмістив цей UIImageView для фону зовні від UIView (кореневий вигляд). А потім призначте backgroundView коду UITableView у коді.

Потім фіксується.


0

Я знайшов рішення.

У моєму випадку я створив вигляд стільника в дошці розкадрування (з увімкненою автоматичною компоновкою), і я визначив користувальницький інтерфейс UITableViewCell у своєму ViewController.m, я повинен перемістити інтерфейс до ViewController.h.


0

З тією ж проблемою я зіткнувся, коли я використовував табло для створення користувацького UITableViewCell. На щастя, я виявив проблему, тому що я випускаю accessoryView ([UITableViewCell setAccessoryView:]) до UIButton, який я додав до комірки.

Так це сталося в моєму проекті під час роботи на iOS6.

Рішення

Я випускаю розетку між accessoryView і моєю кнопкою, яка містила власну комірку.

Пропозиція

Ви не повинні використовувати початкові елементи UITableViewCell і змінювати їх.


0

Цю проблему можна викликати, забувши зателефонувати [super viewDidAppear:]всередину viewDidAppear, але я впевнений, що це не єдина причина.


0

У мене була точно така ж проблема. Ось проблема з моїм проектом:
Коли я працював над Builder інтерфейсу, щоб створити користувальницьку UITableViewCell, я перетягнув View замість осередку перегляду таблиці з панелі колекції об'єктів у Xcode
як клітинку спеціальної таблиці.
Якщо ви опинилися в тій же ситуації, ось таке рішення:
Видаліть подання в програмі інтерфейсів, переконайтеся, що ви перетягуєте комірку перегляду таблиці з області колекції об'єктів і повторюєте власну таблицю комірок таблиці. Ви можете скопіювати об'єкти в старий вигляд і вставити їх на полотно для нового осередку перегляду таблиці.


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

Я змінив відповідь Карла Ліндберга, щоб замінити 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 UITableViewCell . Коли я змінив обмеження, все пішло нормально!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.