"Автоматическая компоновка по-прежнему требуется после выполнения -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+, как это обычно бывает.
Ответ 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. Когда я сменил ограничение, все прошло отлично!