Центрирование подсмотра X в автозапуске вызывает "не подготовленный к ограничению",
У меня есть пользовательский подкласс UIView, который инициализируется через нить.
В -awakeFromNib
, я создаю subview и пытаюсь центрировать его в своем супервизии.
[self setInteralView: [[UIView alloc] init]];
[[self internalView] addConstraint: [NSLayoutConstraint constraintWithItem: [self internalView]
attribute: NSLayoutAttributeCenterX
relatedBy: NSLayoutRelationEqual
toItem: self
attribute: NSLayoutAttributeCenterX
multiplier: 1
constant: 0]];
Это прерывает и вызывает следующий вывод:
2013-08-11 17:58:29.628 MyApp[32414:a0b] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
When added to a view, the constraint items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2013-08-11 17:58:29.630 MyApp[32414:a0b] View hierarchy unprepared for constraint.
Constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
Container hierarchy:
<UIView: 0xc132a40; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0xc132bc0>>
View not found in container hierarchy: <MyView: 0xc1315a0; frame = (-128 -118; 576 804); layer = <CALayer: 0xc131710>>
That view superview: <UIView: 0xc131a70; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0xc131b50>>
Ответы
Ответ 1
Как сказано в сообщении об ошибке, вы должны добавить ограничение к представлению, чтобы представления, связанные с ограничением, - это представление, которое вы добавляете или подзаголовок этого представления. В случае вашего кода выше вы должны добавить это ограничение к self
, а не [self internalView]
. Причина, по которой это не работает, является одним из видов, связанных с ограничением (self
), не в иерархии представлений, если вы рассматриваете только [self internalView]
и ниже).
Подробнее см. раздел раздела документации по методу addConstraint:
.
Вот ваша строка кода, исправленная, как я предлагаю:
UIView* internalView = [[UIView alloc] initWithFrame:CGRectZero];
internalView.translatesAutoresizingMaskIntoConstraints = NO;
[self setInternalView:internalView];
[self addConstraint: [NSLayoutConstraint constraintWithItem: [self internalMapView]
attribute: NSLayoutAttributeCenterX
relatedBy: NSLayoutRelationEqual
toItem: self
attribute: NSLayoutAttributeCenterX
multiplier: 1
constant: 0]];
Ответ 2
Для других, которые приходят сюда: я получил эту ошибку, потому что я добавил ограничения до того, как я добавил subviews в иерархию.
Ответ 3
Короткий ответ: swap родительский и дочерний вид.
Предполагая, что self
является родительским представлением:
Swift
subview.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"H:|-0-[subview]-0-|",
options: .DirectionLeadingToTrailing,
metrics: nil,
views: ["subview":subview]))
Obj-C
[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-0-[subview]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(subview)]];
Ответ 4
Дополнительные советы:
У меня есть недавно разработанное приложение, которое отлично работает на iOS7, но получает ошибку на iOS8. "Иерархия представлений не подготовлена к ограничению".
Прочитайте еще одно сообщение, в котором должно быть добавлено (под) представления перед созданием ограничений. Я сделал это, но все еще получил ошибку.
Затем я понял, что я должен создавать ограничения под - (void) viewDidAppear вместо viewDidLoad
Ответ 5
Это старый вопрос, но я хочу указать эту строку из документов:
При разработке для iOS 8.0 или новее установите для атрибутов свойство isActive значение true вместо прямого вызова метода addConstraint (_:). Свойство isActive автоматически добавляет и удаляет ограничение из правильного представления.
По крайней мере, это приведет к удалению одной точки отказа, так как вам больше не нужно беспокоиться о вызове addConstraint в неправильном представлении
Ответ 6
В моем случае это было решено путем использования корневого представления в качестве контейнера ограничений вместо созданного в настоящее время представления.
Я имею в виду, использовать внутри viewController
view.addConstraints([leftConstraintImage, topConstraintImage])
вместо imageView.addConstraints...
Ответ 7
Как указывает @CharlesA в своем ответе, проблема в том, что добавляемое представление не находится в правильной иерархии представлений. Его ответ хороший, но я собираюсь подробно рассказать о конкретном случае использования, которое вызвало эту проблему для меня:
Это произошло при попытке добавить ограничения в представление, чей контроллер представлений я создал с помощью instantiateViewControllerWithIdentifier
. Чтобы решить проблему, я использовал [childViewController didMoveToParentViewController:self]
. Это добавило представление в иерархию представлений, на которую ссылалось мое ограничение.
Ответ 8
Сначала добавьте свой subView, а затем добавьте свои ограничения следующим образом:
addSubview(yourSubViewHere)
yourSubViewHere.translatesAutoresizingMaskIntoConstraints = false
addConstraint(NSLayoutConstraint(....