2016-02-25 176 views
0

我是一位新手快速開發人員,遵循一個好的iOS 9 Swift書中的代碼示例。本書剛剛演示瞭如何在視圖層次結構的兩個不同分支中的兩個對象(標籤,按鈕)之間添加約束(以代碼形式)。視圖層次結構不準備

myLabel位於頂部視圖控制器中的viewBB容器中。 myButton位於viewBB之外的頂部視圖控制器中。

示例代碼正常工作。但是對於練習,我想在viewBB中創建第二個label2,並將其位置限制爲與myLabel偏移。所以這兩個標籤(我認爲)都在viewBB中。

在代碼中創建label2並在代碼中添加約束可以正常工作。

但是......如果我在界面生成器中創建了label2,並嘗試刪除IB約束並將其替換爲我自己的,那麼構建成功,但應用程序崩潰時出現通常的「視圖層次結構不準備」錯誤。

***有趣的是錯誤消息提到一個標籤和一個按鈕,暗示書本示例代碼(我稱之爲下面的BLOCK 0)是罪犯。

我在做什麼錯? (我讀過的一切,我能找到的錯誤信息,包括在這個論壇4個員額但我不知所措知道爲什麼書代碼失敗。)

錯誤消息:

2016-02-25 12:52:32.796 TwoViewConstraints [5713:1860768] 未對約束準備視圖層次結構:NSLayoutConstraint:0x7c9ce990 UILabel:0x7c9dbec0'Label'.centerX == UIButton:0x7c9deed0'Button'.centerX

當添加到視圖中時,約束條目必須是該視圖的後代(或視圖本身)。如果在組裝視圖層次結構之前需要解析約束,這將會崩潰。打破 - [UIView(UIConstraintBasedLayout)_viewHierarchyUnpreparedForConstraint:]進行調試。從調試

消息:由於終止信號15

這裏是我的代碼:

class ViewController: UIViewController { 

@IBOutlet weak var myLabel: UILabel! 
@IBOutlet weak var myButton: UIButton! 
@IBOutlet weak var centerConstraint: NSLayoutConstraint! 
@IBOutlet weak var viewBB: UIView! 


@IBOutlet weak var lab2cxh: NSLayoutConstraint! 
@IBOutlet weak var lab2cxv: NSLayoutConstraint! 
@IBOutlet weak var label2: UILabel! 


override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view, typically from a nib. 

    // BLOCK 0 - works fine, from the iOS9 book 
    // myLabel and myButton were created with the interface builder 
    // Goal is to remove an IB constraint, and replace it with one 
    // that is built in code. (Because label and buttons are in 
    // different branches of the view hierarchy). 
    // 
    // remove auto center constraint from parent label 
    viewBB.removeConstraint(centerConstraint) 

    // center the label and the button across views 
    let ccx = NSLayoutConstraint(item: myLabel, 
     attribute: NSLayoutAttribute.CenterX, 
     relatedBy: NSLayoutRelation.Equal, 
     toItem: myButton, 
     attribute: NSLayoutAttribute.CenterX, 
     multiplier: 1.0, 
     constant: 0) 
    self.view.addConstraint(ccx) 

//  BLOCK 1 - Create a second label object in code 
//  this code works fine with the two added constraints below 
//  create a second label object and add it to the view 
//  let label2 = UILabel() 
//  label2.translatesAutoresizingMaskIntoConstraints = false 
//  label2.text="Label2" 
//  viewBB.addSubview(label2) 

    // BLOCK 2 - create a second label object in the interface builder 
    // Suggested horiz/vert constraints are set in the IB. 
    // So now I want to remove them, and replace them with my own, 
    // as was done in the Swift book example code in BLOCK 0. 
    // remove original label 2 constraints 
    viewBB.removeConstraint(lab2cxv) 
    viewBB.removeConstraint(lab2cxh) 

    // adding these two constraints works fine when the label2 object 
    // is created in code. But when I create label2 in the interface 
    // builder and try to remove the IB constraints (as was done in the 
    // first block of code), I get the error: 
    // 
    // ... "The view hierarchy is not prepared 
    // for the constraint "Label.CenterX to Button.CenterX", which is 
    // the first block of code. 
    // 
    // NOTE** To me, it looks like the error is coming from the 
    // BLOCK 0 constraint, since it cites a label and a button, not 
    // two labels. 
    // What am I doing wrong? 
    let c2h = NSLayoutConstraint(item: label2, 
     attribute: NSLayoutAttribute.CenterY, 
     relatedBy: NSLayoutRelation.Equal, 
     toItem: myLabel, 
     attribute: NSLayoutAttribute.CenterY, 
     multiplier: 1.0, 
     constant: -50) 
    self.viewBB.addConstraint(c2h) 

    // constrain label 2 to be diagonally left of label one 
    let c2v = NSLayoutConstraint(item: label2, 
     attribute: NSLayoutAttribute.CenterX, 
     relatedBy: NSLayoutRelation.Equal, 
     toItem: myLabel, 
     attribute: NSLayoutAttribute.CenterX, 
     multiplier: 1.0, 
     constant: -100) 
    self.viewBB.addConstraint(c2v) 


} 
+0

嘗試使用'ccx.active = true'而不是'self.view.addConstraint(ccx)'。併爲您的物業使用更好的名稱。 – dasdom

+0

謝謝你回答我的問題。很抱歉地說,但建議的更改無效。這行代碼是直接從書中出來的,並且在我添加下面的代碼之前工作正常。 (授予,cx =約束,c =中心,cxv =約束垂直等對任何人都沒有幫助。)是否有任何讓視圖層次結構沒有準備的好列表,或者我可以學習和遵循的約定? Thx – Kevin

+0

嘗試將所有代碼移出viewDidLoad並放入viewWillAppear。視圖層次結構在viewDidLoad中沒有完全建立。 – Michael

回答

0

我做了整片的代碼一遍,從無到有,和它的工作。去搞清楚。這是正常工作的代碼。據我所知,它幾乎是相同的代碼,除了在這裏和那裏有一個小的名稱更改。

我不知道爲什麼這個版本可以工作,而以前的版本沒有。它讓我想知道Interface Builder設置中是否有不同的東西。

class ViewController: UIViewController { 

@IBOutlet weak var viewbb: UIView! 
@IBOutlet weak var myLabel: UILabel! 
@IBOutlet weak var centerConstraint: NSLayoutConstraint! 
@IBOutlet weak var myButton: UIButton! 

@IBOutlet weak var label2: UILabel! 
@IBOutlet weak var label2centerConstraint: NSLayoutConstraint! 
@IBOutlet weak var label2Yconstraint: NSLayoutConstraint! 

override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view, typically from a nib. 

    // remove the IB centering constraint, then add our own between label and button 
    viewbb.removeConstraint(centerConstraint) 

    // make a new constraint to center label over button 
    let newcon = NSLayoutConstraint(item: myLabel, 
     attribute: NSLayoutAttribute.CenterX, 
     relatedBy: NSLayoutRelation.Equal, 
     toItem: myButton, 
     attribute: NSLayoutAttribute.CenterX, 
     multiplier: 1.0, 
     constant: 0) 
    self.view.addConstraint(newcon) 

    // remove the IB centering constraint, then add our own between label and button 
    viewbb.removeConstraint(label2centerConstraint) 
    viewbb.removeConstraint(label2Yconstraint) 

    // make a new constraint to center label over button 
    let newcon2 = NSLayoutConstraint(item: label2, 
     attribute: NSLayoutAttribute.CenterX, 
     relatedBy: NSLayoutRelation.Equal, 
     toItem: myLabel, 
     attribute: NSLayoutAttribute.CenterX, 
     multiplier: 1.0, 
     constant: -100) // left of mylabel 

    // make a new constraint to center label over button 
    let newcon3 = NSLayoutConstraint(item: label2, 
     attribute: NSLayoutAttribute.CenterY, 
     relatedBy: NSLayoutRelation.Equal, 
     toItem: myLabel, 
     attribute: NSLayoutAttribute.CenterY, 
     multiplier: 1.0, 
     constant: 0) // left of mylabel 

    self.view.addConstraint(newcon3) 
    self.view.addConstraint(newcon2) 
} 
+0

我也嘗試添加兩個新的約束self.viewbb而不是self.view,但它沒有區別。該代碼仍然正常工作。 (回想一下,viewbb是父頂層視圖中的一個視圖容器,viewbb容器包含兩個標籤視圖,所以新的約束可以放在直接父視圖(viewbb)或頂層視圖(self.view)中, 。 – Kevin

相關問題