UIView that creates a sub UIView is generating hierarchy constraint warnings

245 views Asked by At

I am trying to create a TGMapView inside of my UIView. As soon as the TMMapView is created I get this error:

2019-02-04 14:47:22.288241-0500 IOSDemoApp[8325:289276] [LayoutConstraints] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x6000015f0b40 _UILayoutGuide:0x7fe52fc0e750.leading == TrimbleMaps.TMMapView:0x7fe52fc0e320.leading   (inactive)>
    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(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2019-02-04 14:47:22.288477-0500 IOSDemoApp[8325:289276] [LayoutConstraints] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x6000015f0c80 _UILayoutGuide:0x7fe52fc0e750.top == TrimbleMaps.TMMapView:0x7fe52fc0e320.top   (inactive)>
    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(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2019-02-04 14:47:22.288642-0500 IOSDemoApp[8325:289276] [LayoutConstraints] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x6000015f0e10 _UILayoutGuide:0x7fe52ff05670.leading == TrimbleMaps.TMMapView:0x7fe52fc0e320.leading   (inactive)>
    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(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2019-02-04 14:47:22.310967-0500 IOSDemoApp[8325:289276] [LayoutConstraints] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x6000015f0f00 TrimbleMaps.TMMapView:0x7fe52fc0e320.bottom == _UILayoutGuide:0x7fe52ff05670.bottom   (inactive)>
    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(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.

It doesn't seem to matter that the UIView that I'm trying to create here is a TGMapView. If I try to create a plain old UIView I get the same problem.

public class Sample: UIView {

    private var tangramMapView: TGMapView!
    public var trivialView: UIView!

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // both have the same warning/error
        guard let tangramMapView = TGMapView(coder: aDecoder) else { return nil }
        trivialView = UIView.init(coder: aDecoder)

        setup()
    }
}

When I run this, both the TGMapView and UIView inits emit the same warnings (copied above). I expect there to be no warnings and that the UIViews constraints are handled in setup(). I add subviews and set constraints in setup().

Is there something special about adding UIViews to UIViews that I don't know about? Did I do it in the wrong order? Can it not be done before the superView init is done?

EDIT:

Why are you initializing it with Sample views' aDecoder?

No idea. I have it set up in the storyboard and I've set the View in my single view application to be a Sample view. In the debugger I can see that the aDecoder init is being called. I couldn't tell you why the others aren't.

2

There are 2 answers

0
GranolaGuy On BEST ANSWER

I'm answering my question for future users and/or myself when I forget the answer in 2 months.

init?(coder) is used to create your UIView when your UIView is set up in storyboard. The UIView is packaged up and must be decoded. Importantly the coder is only for the UIView that was set up in the storyboard. In this case, that's Sample. Therefor it makes no sense to use coder to init a TGMapView or any other kind of UIView. That's the problem I was having.

The Solution? In my case, I used init(frame) to create any UIView that I wanted inside the view's init?(coder).

6
MCMatan On

Yes, it is ok to add your contains in your init.

The issue you are facing is about the when to add constraints is a relation to subviews.

When specifying constraints between views, they must be subviews of each other (One on top of the other) or both be subviews of the same view (A different view).

And this is exacly what your error is saying:

 The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x6000015f0c80 _UILayoutGuide:0x7fe52fc0e750.top == TrimbleMaps.TMMapView:0x7fe52fc0e320.top   (inactive)>
    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(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.

You are trying to specify TMMapView top constraint relation to a view that is not yet It's relative.

First AddSubviews ,then specify constraints.

EDIT

Why are you initializing it with 'Sample' views aDecoder? You should do that only when subclassing