«Auto Layout все еще требуется после выполнения -layoutSubviews» с подклассом UITableViewCell


115

Используя XCode 4.5 и iOS 6, я разрабатываю приложение с простым табличным представлением с настраиваемыми ячейками. Я делал это сто раз в iOS 5 и ниже, но по какой-то причине новая система autoLayout доставляет мне много проблем.

Я настраиваю табличное представление и ячейку прототипа в IB, добавляю подвиды и подключаю их как IBOutlets, затем настраиваю делегата и источник данных. Однако теперь всякий раз, когда извлекается первая ячейка cellForRowAtIndexPath, я получаю следующую ошибку:

*** Ошибка утверждения в - [ShopCell layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

*** Завершение работы приложения из-за неперехваченного исключения «NSInternalInconsistencyException», причина: «Auto Layout все еще требуется после выполнения -layoutSubviews. Реализация ShopCell -layoutSubviews должна вызывать super.

Я не реализовал метод -layoutSubviews в своей подклассовой ячейке (ShopCell), и даже когда я пытаюсь это сделать и добавить супер-вызов, поскольку он предполагает, я все равно получаю ту же ошибку. Если я удалю подпредставления из ячейки в IB и изменю их на стандартный UITableViewCell, все будет работать так, как ожидалось, хотя, конечно, в моих ячейках не останется данных.

Я почти уверен, что мне не хватает чего-то простого, но я не могу найти никакой документации или руководств, чтобы предположить, что я сделал не так. Любая помощь будет оценена.

Изменить: просто попытался изменить его на UITableViewCell в IB и оставить все подпредставления на месте, все та же ошибка.


lldb [[UIWindow keyWindow] _autoLayoutTrace]Если используется автоматический макет, попробуйте в области отладчика.
A-Live

3
Вы используете UIView для настраиваемой ячейки вместо UITableViewCell? У меня такая же проблема. У меня был UIView для пользовательской ячейки, и я добавлял к ней подвиды. Изменился на UITableViewCell, и все заработало.

Привет, Майк, как ты определяешь торговые точки? Являются ли они свойствами в вашем файле реализации в расширении класса?
kocodude 04

@ A-Live Всякий раз, когда я пытаюсь использовать этот метод, я получаю сообщение об ошибке в отладчике .... этот метод еще действителен? Изменить: Неважно, это строчная буква l в автопластике.
borrrden

снимите флажок autoLayout в инспекторе, затем очистите и запустите. это будет угрюмо работать.
Нико

Ответы:


57

Я столкнулся с той же проблемой при добавлении ограничений в код вручную. В коде я делал следующее:

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

гипотеза

Насколько я могу судить, проблема в том, что при отключении translatesAutoresizingMaskIntoConstraintsUITableViewCell начинает использовать Auto Layout и, естественно, дает сбой, потому что базовая реализация layoutSublayersForLayerне вызывает super. Кто-то с Хоппером или другим инструментом может это подтвердить. Поскольку вы используете 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

По-видимому, реализация layoutSubviews UITableViewCell не вызывает 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 в ячейке таблицы, так как это добавляется как subview к ячейке (тогда как большинство subviews следует добавить в contentView ячейки таблицы, что обычно должно работать лучше).

Примечание. Похоже, что эта ошибка исправлена ​​в iOS7; Мне удалось удалить этот код или, по крайней мере, добавить проверку времени выполнения, чтобы она выполнялась только при работе на iOS6.


Странно то, что для меня он отлично работает с простым UITableViewCell, но не для подкласса ...
borrrden

Можно подумать, но все, что у меня есть, это метод инициализации, ничего больше> <. Я никогда в жизни не переопределял layoutSubviews, ха-ха. Я думаю, проблема в том, что пользовательское представление, которое UITableViewCell использует в качестве корневого представления, не может использовать автоматический макет, потому что оно переопределяет layoutSubviews (поэтому, когда вы пытаетесь добавить ограничения в корневое представление, это не сработает)
borrrden

6
Мне пришлось создать такую ​​категорию по UITableViewтой же причине (iOS 6.1 b1)
Джошуа Дж. Маккиннон

5
Есть ли аналогичное исправление для TableHeaderView, поскольку проблема все еще существует в ios 7?
Softlion

1
Это прекрасно работает. Я столкнулся с этой проблемой, когда попытался центрировать подпредставление UIVIew в UITableView. Даже в iOS 7 такое утверждение происходит. Но этого не происходит в iOS 8, поэтому они, должно быть, устранили ошибку.
Jordan H

33

У меня была такая же ошибка несколько месяцев. Но я нашел, в чем проблема.

Когда я создаю файл IB, UIViewон уже добавлен. Если вы используете это представление, приложение не вылетает при отключении автоматического макета (но есть и другие проблемы). При использовании автоматической компоновки, вы должны выбрать правильный вид в библиотеке объектов: UITableViewCell.

На самом деле, вы должны всегда использовать этот пункт , потому что все подвиды добавляют к contentViewиз UITableViewCell.

Вот и все. Все будет хорошо.


Это не должен быть принятым ответом, потому что вопрос не в реализации с использованием IB, а потому, что эта проблема может возникнуть, когда вы не используете IB. Если вы делаете свои взгляды программно, ответ @ PhilLoden более жизнеспособен.
Эрик

Я не понял ответа. может кто-нибудь объяснить более четко? спасибо
hasan

Думаю, я имею на это право. Достаточно ли проверить класс att. в инспекторе удостоверений в построителе интерфейсов? или добавленное было другого типа и класса att. был обновлен позже? это тоже вызывает проблему?
hasan

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

17

У меня была UITableViewHeaderFooterViewтакая же проблема с custom + xib.

Я видел здесь несколько ответов, но обнаружил, какая реализация -layoutSubviewsв моем пользовательском классе представления нижнего колонтитула устраняет проблему:

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

1
Учтите , что это может привести к бесконечной петле и , наконец , EXC_BAD_ACCESS KERN_PROTECTION_FAILURE
MBI

15

Я видел это в результате изменения ограничений в моей реализации layoutSubviews. Перемещение вызова к super с начала до конца метода устранило проблему.


Это сработало для меня. У меня есть собственный UICollectionViewCell, который я форматирую в layoutSubviews. Кто-нибудь знает, почему это решение работает?
STANGMMX

@STANGMMX, ответ A'sa Dickens объясняет, почему.
Фабио Оливейра

15

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


Спасибо. Мне помогает, вчера (на iOS 7) столкнулся с этой проблемой. это помогает для iOS 7.
Александр

@MaciejSwic см. Мой ответ вверху.
Sound Blaster

Это сработало для меня! Использование iOS 7.1 с Swift. Я удалял и добавлял ограничение для viewDidLayoutSubviews. Я удалил супер-вызов, но он все еще не работал, но это решение помогло! дайте этому динозавру лист! :)
jomafer 05

У меня тоже работало на 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.
Guilherme

Супер! также @Arnaud respone ниже
Лаббо

7

Я решил проблему, отключив «Автоформат» для всех подпредставлений моей пользовательской ячейки табличного представления.

В xib для настраиваемой ячейки выберите подпредставление и снимите флажок File Inspector> Interface Builder Document> Use Autolayout


4
Я сделал то же самое. Хотя это не совсем решение, если вы хотите использовать
автопрокладку

7

У меня была подобная проблема не на себе, UITableViewCellа скорее на UITableViewсебе. Поскольку это первый результат в Google, я выложу его здесь. Оказалось, что это viewForHeaderInSectionбыла проблема. Я создал UITableViewHeaderFooterViewи набор translatesAutoresizingMaskIntoConstraintsдля NO. А теперь самое интересное:

IOS 7:

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

Если я сделаю это, приложение вылетит с

Auto Layout по-прежнему требуется после выполнения -layoutSubviews. Реализация -layoutSubviews в UITableView должна вызывать 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 / раскадровки, которое использует автоматический макет в качестве подпредставления для другого представления, это исключение может быть сгенерировано, в зависимости от того, как настроены ваши ограничения. Я предполагаю, что ограничения, созданные в IB, - это то, что создает проблемы при программном добавлении представления в качестве подпредставления, поскольку оно затем поддерживает ограничения из viewA -> viewB, в то время как вы можете добавить viewB как подвид viewC. Вы поняли (это предложение даже меня сбивает с толку)?

В моей ситуации - поскольку проблема была вызвана очень простыми представлениями - я создавал представления программно, а не в IB. Это решило ее. Вы можете извлечь эти представления в другие файлы 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 (корневое представление) и сбросил (удалил) все ссылки автоматического макета на этот 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

У меня была точно такая же проблема. Вот проблема с моим проектом:
Когда я работал на Interface Builder для создания пользовательских UITableViewCell, я перетащил View вместо Table View Cell из панели коллекции объекта в Xcode
как ячейки пользовательских таблиц.
Если вы находитесь в такой же ситуации, вот решение:
удалите представление в построителе интерфейса, убедитесь, что вы перетащили ячейку табличного представления из панели коллекции объектов и повторите создание настраиваемого представления ячейки таблицы. Вы можете скопировать объекты в старом представлении и вставить их на холст для новой ячейки табличного представления.


0

У меня была очень похожая проблема с представлением нижнего колонтитула таблицы, которое я устанавливал в Xcode 6, iOS 7+. Решение было в формате файла пера. Очевидно, он застрял в формате Xcode 4 или что-то в этом роде. Изменение настроек файла на «открывается в: Xcode 6.0» (или по умолчанию, если на то пошло) мгновенно исправило это. Решение нашел случайно: это сводило меня с ума, поэтому я удалил весь файл и создал заново, очевидно, с настройками по умолчанию. Я понятия не имею, почему простое редактирование файла в последней версии Xcode не преобразовало его в формат Xcode 5+, как это обычно бывает.

е


0

У меня была такая же проблема. Я зашел в свой DetailViewController и переименовал идентификатор в UIView. Ранее он был на UITableView. Это устранило проблему. Эта проблема не обязательно должна быть в вашем DetailViewController. Может быть в любом другом. Попробуйте переименовать его в уважаемый идентификатор.


0

У меня была аналогичная проблема со статическими ячейками табличного представления в IB. В одной из ячеек было вложенное представление, в котором был класс, ошибочно измененный на подкласс 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 UITableViewCell . Когда я изменил ограничение, все прошло нормально!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.