Центрирование подсмотра 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 является родительским представлением:

  • bad: [subview addConstraint [NSLayoutConstraint constraintWithItem:self...

  • хороший: [self addConstraint [NSLayoutConstraint constraintWithItem:subview...


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(....