為什麼出現一種約束叫做 NSIBPrototypingLayoutConstraint
一般來講,約束的型別應該都是 NSLayoutConstraint,但是從 Xcode 4 開始,增加了 Auto Layout 功能時,考慮到當開發者在 IB 中建立 View 後,沒有顯示的主動新增任何約束,會導致檢視無法顯示,因此 IB 會根據你拖動 View 的位置,自動的幫你加上約束,避免檢視無法顯示,因為這種約束是 IB 自動新增的,因此類名叫 NSIBPrototypingLayoutConstraint,並且這種約束無法通過 NSLog(@"%@", self.constraints);
列印出來。
深層次的原因
一般來講,這種情況下,對當前 View 設定
view.translatesAutoresizingMaskIntoConstraints = NO;
複製程式碼
即可。
對於 translatesAutoresizingMaskIntoConstraints
屬性,官方文件時這樣寫的:
Discussion
If this property’s value is YES, the system creates a set of constraints that duplicate the behavior specified by the view’s autoresizing mask. This also lets you modify the view’s size and location using the view’s frame, bounds, or center properties, allowing you to create a static, frame-based layout within Auto Layout.
Note that the autoresizing mask constraints fully specify the view’s size and position; therefore, you cannot add additional constraints to modify this size or position without introducing conflicts. If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set this property to NO, and then provide a nonambiguous, nonconflicting set of constraints for the view.
By default, the property is set to YES for any view you programmatically create. If you add views in Interface Builder, the system automatically sets this property to NO.
簡單翻譯一下,意思是說:
使用程式碼建立 View 時,這個屬性預設是 YES,然後你就可以通過設定其 frame、bounds、center 等屬性,自動的轉換為 autoLayout 的約束。保證檢視約束的完整性,能夠很好的顯示。
但是,你一旦這麼做了,那麼就不能額外給這個 View 新增約束了。因為,這個 View 已經有了 transfer 過來的約束,你再新增的話,約束將會衝突。
如果你希望能夠手動地新增約束,來滿足需求,那麼就需要設定 translatesAutoresizingMaskIntoConstraints = NO
。
在使用 IB 時,這個屬性預設是 NO。
一點疑惑
官方的說法中,在 IB 中,這個屬性應該是 NO,但是我通過 xib 建立的 UITableViewCell ,在awakeFromNib
方法中,列印出該屬性是 YES。
就是因為這樣,才導致我在awakeFromNib
方法中使用 masonry 新增的約束有了衝突。
解決問題的最終辦法
在 IB 中,顯示的為 view 新增一些約束,然後全部選擇這些約束,在 File Inspector
中,勾選 Remove at build time
;

為什麼上述方法可以解決問題
問題的根本是 IB 自動建立了我們不想要的約束,IB 自動建立的原因是 view 上沒有約束,因此我們隨意給 view 新增一些無用的約束,然後讓其在 building 時刪除掉。
這樣子,當程式碼執行到 masonry make 建立約束時,這個 view 將是一個乾淨的 view。
Placeholder : Remove At build time
這個屬性呢,其實本來的使用場景是這樣:
在開發過程中,有時候需要預覽一些佈局,那麼在 Storyboard 上新增約束,就會很方便,這樣子在不執行程式碼的情況下,就能夠測試驗證我們的約束是否正確。
但是呢,在實際開發中,很可能大家覺得在 storyboard 上新增約束比較麻煩,團隊之間協作不好,因此希望能夠使用程式碼建立約束,比如 masonry 這種工具。
很簡單,只需要在執行時,將 storyboard 中新增的約束全部刪除掉。這樣子,storyboard 中新增的約束不會對程式碼新增的約束造成任何影響。另一方面,在 storyboard 中佈局可以更加方便,且 storyboard 中不會出現一堆關於約束的 warning。
後記
有什麼問題,可以留言,我會盡快回復~