由於種種原因,所以到目前為止,我在公司的專案還是沒有用 Interface Builder,所有的 UI 完全用程式碼一行一行刻出來,當然這也包含 auto layout 相關的程式碼,那這些程式碼應該要放哪裡呢?

如果是一個 UIViewController 的話,程式碼架構大概長這樣:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupConstraints];
}

- (void)setupConstraints {
    // Create and add layout constraints to view and subviews.
}

如果是 UIView 的話,大概是這樣:

@interface CustomView()
@property (nonatomic, assign) BOOL didSetupConstraints;
@end

@implementation CustomView
- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Do something....
        [self setNeedsUpdateConstraints];
        [self updateConstraintsIfNeeded];
    }
    return self;
}

- (void)updateConstraints {
    if (!self.didSetupConstraints) {
        // Create and add constraints to self and subviews.
        self.didSetupConstraints = YES;
    }
    [super updateConstraints];
}
@end

我在網路上看到的作法也都是這樣。UIViewController 還沒什麼問題,只是 UIView 還要多一個 BOOL 來判斷要不要加入 constraints,讓我感到很不自然,全身不舒服。

最近在爬文的時候,看到這一篇文章,裡頭提到了一段來自 Apple 工程師的回應:

In general, if the constraints will only be created once, it should be done in an initialization method (such as -init or -viewDidLoad, and so forth). Save -updateConstraints for things that are expected to change over the course of running the App.

如果你不會在程式運行途中去新增或移除 constraints,那就把建立 constraints 的工作放在 initviewDidLoad 階段。中途會新增或移除的動作才放到 updateConstraints。你可以建立 constraint 之後再修改它的 constant 屬性,這不算是新增或移除 constraint。

嗯,所以之後我可以開心的寫 auto layout 了:)

Update:
今天看到這一篇文章還有 WWDC 2015 的影片,覺得應該要更新一下我的結論:updateConstraints 因為會一次處理所有的 constraint,所以它的效能比較好,適合在需要「大量的新增、修改、刪除 constraints」的時候使用。如果你沒有遇到效能問題,那可以不用它。