"Автоматическая компоновка по-прежнему требуется после выполнения -layoutSubviews" с подклассом UITableViewCell

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

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

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

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

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

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

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

Ответы

Ответ 1

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

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

Гипотезы

Из того, что я могу сказать, проблема в том, что при отключении translatesAutoresizingMaskIntoConstraints UITableViewCell начинает использовать автоматическую компоновку и, естественно, терпит неудачу, потому что базовая реализация layoutSublayersForLayer не вызывает супер. Кто-то с Hopper или другим инструментом может подтвердить это. Поскольку вы используете IB, вам, вероятно, интересно, почему это проблема... и что, поскольку использование IB автоматически отключает translatesAutoresizingMaskIntoConstraints для представлений, в которые он добавляет ограничения (он автоматически добавит ограничение ширины и высоты на их место).

Решение

Мое решение состояло в том, чтобы переместить все в contentView.

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

Я не уверен на 100%, если это будет работать в Interface Builder, но если вы выталкиваете все из своей ячейки (при условии, что у вас есть что-то прямо на ней), тогда это должно сработать. Надеюсь, это поможет вам!

Ответ 2

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

В xib для пользовательской ячейки выберите подвью и снимите флажок "Инспектор файлов > Документ конструктора интерфейсов > Использовать автоопределение

Ответ 9

У меня была аналогичная проблема не на 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.

Ответ 10

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

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

Ответ 11

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

Мне пришлось отделять свои ячейки от независимых ножей, которые не используют AutoLayout.

Пусть надеется, что Apple очистит этот беспорядок.

Ответ 12

Я столкнулся с этим, потому что сначала я добавил UIView вместо UITableViewCell в xib файл.

Ответ 13

Я устранил эту ошибку, отсоединив коннектор backgroundView от моего фона UIImageView и accessoryView от моих настроек UIButton. Я подозреваю, что они не предназначены для использования так, как я их использовал.

Ответ 14

Сегодня я столкнулся с этим вопросом. До сих пор у меня был некоторый опыт использования прототипов подклассов UITableViewCell, но я никогда не сталкивался с этой проблемой. Что было отличным в той ячейке, с которой я работал, было то, что у меня был IBOutlet для -backgroundView, который я использовал для окраски ячейки. Я обнаружил, что если бы я создал новое свойство и все еще добавлял новый UIView, который растягивал промежуток всей ячейки, это утверждение уходило. Чтобы убедиться, что это была причина, я вернулся к прикреплению этого вида к выходу backgroundView, и это утверждение появилось снова. До сих пор никаких других проблем с использованием AutoLayout в подклассе прототипа UITableViewCell, поскольку я сделал это изменение.

Ответ 15

Добавьте свои subviews в contentView ячейки вместо самой ячейки. Поэтому вместо:

[self addSubview:someView];

вы должны использовать

[self.contentView addSubview:someView];

Ответ 16

У меня не было подходящего решения для этой проблемы, но вы можете исправить ее с помощью фреймов и не устанавливать для 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];

Ответ 17

Я испытываю то же самое. Оказалось, что если вы программно добавите subview из вашего ShopCell.xib/раскадровки, который использует автоматическую компоновку, в качестве подсмотра для другого представления, это исключение может быть выбрано в зависимости от того, как настроены ваши ограничения. Я предполагаю, что ограничения, создаваемые в IB, создают проблемы при программном добавлении представления в качестве подчиненного, поскольку тогда он ограничивает ограничения на viewA → viewB, в то время как вы можете добавить viewB в качестве поднабора viewC. Вы получили это (это предложение даже запутывает меня)?

В моей ситуации - поскольку это были очень простые представления, вызвавшие проблему, я создал представления программно, а не в IB. Это решило. Вы можете извлечь эти представления в другие файлы xib и отключить автоматическую компоновку для них. Думаю, это сработает.

Ответ 18

В некоторых ситуациях это легко решает проблему компоновки (в зависимости от вашего макета). Внутри вашего подкласса UITableView, либо в awakeFromNib, либо в init, установите маску авторезистировки:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

По умолчанию def установлено значение UIViewAutoresizingNone

Ответ 19

В моем случае

Указанный UIImageView для автоматического макета для UITableView присваивается backgroundView UITableView.

self.tableView.backgroundView = self.tableBackgroundImageView;

Итак, я удалил UIImageView для backgroundView из UIView (Root view) и reset (удалить) все ссылки на автомаршрут к этому UIImageView. Я поместил этот UIImageView для фона снаружи из UIView (корневой вид). А затем назначьте backgroundView UITableView в коде.

Тогда фиксировано.

Ответ 20

Я нашел решение.

В моем случае я создал представление ячейки в раскадровке (с включенным автоматическим макетом), и я определил пользовательский интерфейс UITableViewCell в моем ViewController.m, мне нужно переместить интерфейс в ViewController.h.

Ответ 21

Я столкнулся с той же проблемой, когда я использую раскадровку для создания пользовательского UITableViewCell. К счастью, я нашел проблему, потому что я вывожу аксессуар ([UITableViewCell setAccessoryView:]) в UIButton, который я добавил в ячейку.

Итак, это произошло в моем проекте при запуске на iOS6.

Решение

Я выпускаю розетку между аксессуаром и моей кнопкой, которая содержала пользовательскую ячейку.

Предложение

Вы не должны использовать собственные элементы UITableViewCell и изменять он.

Ответ 22

Эта проблема может быть вызвана забыванием вызвать [super viewDidAppear:] внутри viewDidAppear, но я уверен, что это не единственная причина.

Ответ 23

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

Ответ 24

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

f

Ответ 25

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

Ответ 26

У меня была аналогичная проблема с ячейками со статическими таблицами в IB. Одна из ячеек имела подвид, у которого был класс, который был ошибочно изменен на подкласс UITextfield. Компилятор не выдавал никаких предупреждений/ошибок. Но во время выполнения система не смогла загрузить контроллер представления с вышеупомянутым сбоем.

Ответ 27

Проблема заключается в последовательности вызовов компоновки в subviews:

Отъезд

Показывает в iOS < 8

Ответ 28

Решение: изменить ограничения перед вызовом super layoutSubviews

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

Ответ 29

Я изменил ответ Карла Линдберга, чтобы вместо этого заменить 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"

Ответ 30

Я встретил ту же проблему и, наконец, нашел причину, я добавил одно ограничение на UITableViewCell, которое должно быть UITableViewCell contentView. Когда я сменил ограничение, все прошло отлично!