重寫 loadView 時,self.view 尚未創建,frame 未知。直接 [[UIView alloc] init] 或 initWithFrame:CGRectZero 哪個正確?
initWithFrame:是 UIView 的**指定初始化器**。所有自定義初始化最終必須調用它。傳遞CGRectZero表示「稍後通過 Auto Layout 或手動設置 frame 確定幾何屬性」。
- (void)loadView {
// 1. 創建根視圖,frame 為 Zero(將由 Auto Layout 決定最終大小)
UIView *containerView = [[UIView alloc] initWithFrame:CGRectZero];
containerView.backgroundColor = [UIColor whiteColor];
containerView.translatesAutoresizingMaskIntoConstraints = NO; // 啟用 Auto Layout
// 2. 添加子視圖、設置約束
UILabel *label = [[UILabel alloc] init];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.text = @"Hello";
[containerView addSubview:label];
[NSLayoutConstraint activateConstraints:@[
[label.centerXAnchor constraintEqualToAnchor:containerView.centerXAnchor],
[label.centerYAnchor constraintEqualToAnchor:containerView.centerYAnchor]
]];
// 3. 賦值給 self.view
self.view = containerView;
}
initWithFrame:CGRectZero:滿足指定初始化器契約,避免未定義行為。translatesAutoresizingMaskIntoConstraints = NO:手動佈局時關閉 autoresizing mask 轉換,防衝突。self.view.frame,Auto Layout 引擎計算最終佈局。| 方法 | 是否指定初始化器 | frame 初始值 | 推薦度 |
|---|---|---|---|
[[UIView alloc] init] | 否(便利初始化器,內部調用 initWithFrame:CGRectZero) | CGRectZero | 可用,但非標準 |
[[UIView alloc] initWithFrame:CGRectZero] | 是 | CGRectZero | ✅ 標準、明確 |
[[UIView alloc] initWithFrame:someRect] | 是 | someRect | 僅當 frame 已知且不使用 Auto Layout |
override func loadView() {
let containerView = UIView(frame: .zero)
containerView.backgroundColor = .white
containerView.translatesAutoresizingMaskIntoConstraints = false
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello"
containerView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
])
self.view = containerView
}
**initWithFrame:CGRectZero 是 loadView 中創建根視圖的正規做法**。配合 Auto Layout 約束,frame 由系統自動計算,無需手動預測尺寸。