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

31 ответ

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

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

гипотеза

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

Решение

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

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

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

По-видимому, реализация 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[self addSubview:someView];

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

[self.contentView addSubview:someView];

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

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

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

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

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

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

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

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

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

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

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

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

self.tableView.backgroundView = self.tableBackgroundImageView;

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

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

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

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

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

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

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

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

Решение

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

Предложение

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

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

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

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

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

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

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

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

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

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

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

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

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

Другие вопросы по тегам