it-roy-ru.com

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

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

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

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

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

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

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

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

113
Mike Mayo

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

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

Гипотеза

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

Решение

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

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

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

57
Malaxeur

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

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

53
Carl Lindberg

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

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

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

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

33
Arnaud

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

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

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

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

15
Keller

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

15
Phil Loden

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

14
Trunal Bhanse

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

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

7
Johno

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

IOS 7:

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

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

Автоматическое расположение все еще требуется после выполнения -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.

7
testing

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

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

5
Maksymilian Wojakowski

Добавьте ваши подпредставления в contentView ячейки вместо самой ячейки . Вместо:

[self addSubview:someView];

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

[self.contentView addSubview:someView];

2
Christian Aberger

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

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

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

2
Lee Probert

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

1
mjmdavis

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

1
Eric Schramm

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

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

1
Owen Godfrey

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

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

0
Nim Thitipariwat

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

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

0
Alfy

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

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

Решение

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

Предложение

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

0
jiwq

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

Проверять, выписываться

Появляется в iOS <8

0
Shanu ji

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

f

0
user3099609

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

0
Yannick Winters

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

0
RandomDude

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

0
us_david

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

0
michaelsnowden

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

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

0
Kasper Munck

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

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}
0
abuharsky

В моем случае,

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

self.tableView.backgroundView = self.tableBackgroundImageView;

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

Тогда исправлено.

0
Conan Kim

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

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

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

0
Arie Litovsky