Centrar la X de la subvista en el diseño automático arroja “no preparado para la restricción”

Tengo una subclase UIView personalizada que se está inicializando a través de un plumín.

En -awakeFromNib , estoy creando una subvista e intentando centrarla en su supervista.

 [self setInteralView: [[UIView alloc] init]]; [[self internalView] addConstraint: [NSLayoutConstraint constraintWithItem: [self internalView] attribute: NSLayoutAttributeCenterX relatedBy: NSLayoutRelationEqual toItem: self attribute: NSLayoutAttributeCenterX multiplier: 1 constant: 0]]; 

Esto se rompe y causa el siguiente resultado:

 2013-08-11 17:58:29.628 MyApp[32414:a0b] The view hierarchy is not prepared for the constraint:  When added to a view, the constraint's 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:  Container hierarchy: <UIView: 0xc132a40; frame = (0 0; 0 0); clipsToBounds = YES; layer = > View not found in container hierarchy: <MyView: 0xc1315a0; frame = (-128 -118; 576 804); layer = > That view's superview: <UIView: 0xc131a70; frame = (0 0; 320 568); autoresize = W+H; layer = > 

    Como indica el error, debe agregar la restricción a una vista de manera que las vistas involucradas en la restricción sean la vista a la que la está agregando o una subvista de esa vista. En el caso de su código anterior, debe agregar esa restricción a self , en lugar de [self internalView] . El motivo por el que no funciona como está escrito es que una de las vistas involucradas en la restricción ( self ) no está en la jerarquía de vistas si solo se tiene en cuenta [self internalView] y más abajo).

    Para obtener más detalles, consulte la sección de discusión de la documentación sobre el método addConstraint:

    Aquí está su línea de código, corregida como sugiero:

     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]]; 

    Para otros que vienen aquí: obtuve este error porque agregué las restricciones antes de agregar las subvistas a la jerarquía.

    Respuesta corta : cambiar la vista padre e hijo.
    Asumir self es la vista principal:

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

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


    Rápido

     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)]]; 

    Consejos adicionales:

    Tengo una aplicación recientemente desarrollada que funciona bien en iOS7 pero que tiene un error en iOS8 “La jerarquía de vistas no está preparada para la restricción”.

    Lea alguna otra publicación que dice que las (sub) vistas deben agregarse antes de crear restricciones. Lo hice pero aún así obtuve el error.

    Luego descubrí que debería crear restricciones bajo – (nulo) viewDidAppear en lugar de viewDidLoad

    Esta es una vieja pregunta, pero quiero señalar esta línea de los documentos:

    Al desarrollar para iOS 8.0 o posterior, establezca la propiedad isActive de la restricción en verdadero en lugar de llamar directamente al método addConstraint (_ :). La propiedad isActive agrega y elimina automáticamente la restricción de la vista correcta.

    Por lo menos, esto eliminará un punto de falla ya que ya no necesita preocuparse por llamar a addConstraint en la vista incorrecta

    Como señala @CharlesA en su respuesta, el problema es que la vista que está agregando no está en la jerarquía de vista correcta. Su respuesta es buena, pero voy a detallar un caso de uso particular que me causó este problema:

    Esto sucedió cuando intenté agregar restricciones a una vista cuyo controlador de vista había creado una instancia usando instantiateViewControllerWithIdentifier . Para resolver el problema, utilicé [childViewController didMoveToParentViewController:self] . Esto agregó la vista en la jerarquía de vista a la que mi restricción hizo referencia.

    En mi caso, se resolvió utilizando la vista raíz como un contenedor de restricciones en lugar de una vista creada actualmente.

    Quiero decir, usar inside viewController

    view.addConstraints([leftConstraintImage, topConstraintImage]) lugar de imageView.addConstraints...