视图层次结构即使在添加子视图后也未准备好约束

时间:2015-10-06 10:02:19

标签: ios swift autolayout

我正在尝试实现一个集合视图,其中每个单元格都有可变数量的UIButton实例,端对端水平放置。

因为按钮的数量是动态的,所以我在运行时实例化按钮并以编程方式添加自动布局约束(第一次尝试这个)。

这是我的代码:

class MyCustomCell: UICollectionViewCell
{
    var buttonTitles:[String]?

    var buttons = [UIButton]()

    override func didMoveToSuperview()
    {
        super.didMoveToSuperview()

        guard let titles = buttonTitles else {
            return
        }

        for button in buttons {
            button.removeFromSuperview()
        }

        buttons.removeAll()


        self.translatesAutoresizingMaskIntoConstraints = false


        // FIRST LOOP: CREATE/ADD BUTTONS:

        for (index, title) in titles.enumerate(){

            let button = UIButton(type: UIButtonType.Custom)

            button.translatesAutoresizingMaskIntoConstraints = false

            button.setTitle(title, forState: .Normal)
            button.tag = index

            addSubview(button)
            buttons.append(button)
        }

        // SECOND LOOP: ADD CONSTRAINTS:

        for (index, button) in buttons.enumerate(){

            // Vertical Constaints (common to all buttons)

            button.addConstraint(
                NSLayoutConstraint(
                    item: self,
                    attribute: NSLayoutAttribute.TopMargin,
                    relatedBy: NSLayoutRelation.Equal,
                    toItem: button,
                    attribute: NSLayoutAttribute.Top,
                    multiplier: 1,
                    constant: 0
                )
            )

            button.addConstraint(
                NSLayoutConstraint(
                    item: self,
                    attribute: NSLayoutAttribute.BottomMargin,
                    relatedBy: NSLayoutRelation.Equal,
                    toItem: button,
                    attribute: NSLayoutAttribute.Bottom,
                    multiplier: 1,
                    constant: 0
                )
            )


            // Horizontal Constriants

            if index == 0 {

                // First - Constrain left to parent (self):

                button.addConstraint(
                    NSLayoutConstraint(
                        item: self,
                        attribute: NSLayoutAttribute.LeftMargin,
                        relatedBy: NSLayoutRelation.Equal,
                        toItem: button,
                        attribute: NSLayoutAttribute.Left,
                        multiplier: 1,
                        constant: 0
                    )
                )
            }
            else {
                // Not first - Constrain left to previous button:

                let previousButton = self.subviews[index - 1]

                button.addConstraint(
                    NSLayoutConstraint(
                        item: previousButton,
                        attribute: NSLayoutAttribute.LeftMargin,
                        relatedBy: NSLayoutRelation.Equal,
                        toItem: button,
                        attribute: NSLayoutAttribute.Left,
                        multiplier: 1,
                        constant: 0
                    )
                )

                if index == (titles.count - 1) {

                    // Last: Constrain right

                    button.addConstraint(
                        NSLayoutConstraint(
                            item: self,
                            attribute: NSLayoutAttribute.RightMargin,
                            relatedBy: NSLayoutRelation.Equal,
                            toItem: button,
                            attribute: NSLayoutAttribute.Right,
                            multiplier: 1,
                            constant: 0
                        )
                    )
                }
            }
        }
    }
}

当我尝试添加第一个约束时,我会抛出此异常:

The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7f9702d19610 MyAppName.MyCustomCell:0x7f9703a690e0.topMargin == UIView:0x7f9702d163e0.top>
    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.
2015-10-06 18:39:58.863 Meeting Notes[15219:1817298] View hierarchy unprepared for constraint.
    Constraint: <NSLayoutConstraint:0x7f9702d19610 MyAppName.MyCustomCell:0x7f9703a690e0.topMargin == UIView:0x7f9702d163e0.top>
    Container hierarchy: 
<UIView: 0x7f9702d163e0; frame = (0 0; 97 60); gestureRecognizers = <NSArray: 0x7f96fb64b5c0>; layer = <CALayer: 0x7f96fb606880>>
    View not found in container hierarchy: <MyAppName.MyCustomCell: 0x7f9703a690e0; baseClass = UICollectionViewCell; frame = (103 0; 97 60); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x7f96fb64bcd0>>
    That view's superview: <UICollectionView: 0x7f96fb8cc800; frame = (0 172; 1024 596); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7f9701f813f0>; layer = <CALayer: 0x7f9701f865c0>; contentOffset: {0, 0}; contentSize: {1024, 182}> collection view layout: <UICollectionViewFlowLayout: 0x7f9701f8df50>
(lldb)

正如所讨论的here和其他类似的问题,当约束中涉及的视图不是父子关系时,会发生这种情况。但是,在添加任何约束之前,我已经添加了所有子视图(我将循环拆分为两个)。此外,整个代码在单元格didMovetoSuperview内运行,因此单元格本身不是孤立的......

我缺少什么?

1 个答案:

答案 0 :(得分:6)

请参阅错误消息:

  

添加到视图时,约束的项必须是该视图的后代(或视图本身)

在您的情况下,应将所有约束添加到self

self.addConstraint( ...
相关问题