loadView VS viewDidLoad

本文解析了iOS开发中viewDidLoad与loadView两个方法的区别及应用场景。viewDidLoad仅在从nib文件初始化视图时调用,而loadView则在视图控制器的view为nil时调用,适用于以编程方式创建视图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iPhone开发必不可少的要用到这两个方法。 他们都可以用来在视图载入的时候,初始化一些内容。 但是他们有什么区别呢?

viewDidLoad 此方法只有当view从nib文件初始化的时候才被调用。

loadView 此方法在控制器的view为nil的时候被调用。 此方法用于以编程的方式创建view的时候用到。 如:

  1.  
  2. - ( void ) loadView {
  3.     UIView *view = [ [ UIView alloc] initWithFrame:[ UIScreen
  4. mainScreen] .applicationFrame] ;
  5.     [ view setBackgroundColor:_color] ;
  6.     self.view = view;
  7.     [ view release] ;
  8. }
  9.  

你在控制器中实现了loadView方法,那么你可能会在应用运行的某个时候被内存管理控制调用。 如果设备内存不足的时候, view 控制器会收到didReceiveMemoryWarning的消息。 默认的实现是检查当前控制器的view是否在使用。 如果它的view不在当前正在使用的view hierarchy里面,且你的控制器实现了loadView方法,那么这个view将被release, loadView方法将被再次调用来创建一个新的view。

 

--------------------------------------------------------------------------------------------------------------------------------------------

Don't read self.view in -loadView. Only set it, don't get it.

The self.view property accessor calls -loadView if the view isn't currently loaded. There's your infinite recursion.

The usual way to build the view programmatically in -loadView, as demonstrated in Apple's pre-Interface-Builder examples, is more like this:

UIView
 
*
view 
=
 
[[
UIView
 alloc
]
 init
...];

...
[ view addSubview : whatever ];
[ view addSubview : whatever2 ];
...
self . view = view ;
[ view release ];

And I don't blame you for not using IB. I've stuck with this method for all of Instapaper and find myself much more comfortable with it than dealing with IB's complexities, interface quirks, and unexpected behind-the-scenes behavior.

<think>我们正在讨论iOS开发中UIViewController的viewDidLoad方法。根据引用[1]和引用[2],viewDidLoadUIViewController生命周期中的一个重要方法。 引用[1]指出:无论是从xib文件加载视图还是自己创建视图,viewDidLoad方法都会被调用,而且是在视图已经被加载后调用。同时强调,任何UI控件的创建都不应该在viewDidLoad方法中实现,因为这是xib文件或者loadView方法的任务。viewDidLoad只是通过nib或者loadView方法加载视图的一种拓展和补充机制。 引用[2]详细描述了UIViewController的生命周期,其中viewDidLoadloadView之后被调用,此时整个视图层次(view hierarchy)已经放到内存中,可以移除一些视图,修改约束,加载数据等。 因此,我们可以总结如下: 1. viewDidLoad的调用时机:在视图控制器的视图被加载到内存之后调用,且在整个视图控制器的生命周期中只调用一次(除非视图被从内存中清除,但通常不会)。 2. 作用:用于进行一些初始化操作,但这些操作不应该包括创建视图层次(因为视图层次已经在loadView或从nib/storyboard加载完成),而应该是对已经加载的视图进行配置,例如设置控件的属性、加载数据、添加手势等。 3. 注意事项:避免在viewDidLoad中执行耗时操作,因为这会延迟视图的显示。如果确实需要执行耗时操作,应该使用异步方式。 使用场景: - 配置界面上的控件(例如设置文本、颜色、字体等) - 初始化数据模型,并更新界面 - 添加手势识别器 - 注册通知 - 设置委托 代码示例: ```objective-c - (void)viewDidLoad { [super viewDidLoad]; // 设置标题 self.title = @"首页"; // 设置背景色 self.view.backgroundColor = [UIColor whiteColor]; // 配置一个标签 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 200, 40)]; label.text = @"Hello, World!"; [self.view addSubview:label]; // 加载数据 [self loadData]; } - (void)loadData { // 异步加载数据 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 模拟网络请求 [NSThread sleepForTimeInterval:2.0]; dispatch_async(dispatch_get_main_queue(), ^{ // 更新UI }); }); } ``` 注意:在viewDidLoad中,视图的几何属性(如frame、bounds)可能还没有确定,因为此时还没有进行自动布局(Auto Layout)的计算。因此,如果代码依赖于视图的尺寸,最好在viewDidLayoutSubviews中处理。 另外,引用[1]特别强调,UI控件的创建不应该在viewDidLoad中,而应该在loadView方法中(如果是通过代码创建视图)或者由xib/storyboard完成。viewDidLoad只是对已经存在的视图进行配置。 总结:viewDidLoad是进行视图控制器初始化设置的重要方法,但要注意它只被调用一次,并且此时视图的几何属性可能还未确定。 相关问题: 1. viewDidLoadloadView方法有什么区别? 2. 在viewDidLoad中为什么不能设置视图的frame? 3. 如果视图控制器是从storyboard创建的,viewDidLoad中应该做什么? 4. viewDidLoad和viewWillAppear的区别是什么? 5. 在viewDidLoad中执行网络请求是否合适?</think>### iOS开发中 `viewDidLoad` 方法详解 `viewDidLoad` 是 `UIViewController` 生命周期中的核心方法,在视图加载完成后触发。以下是详细解析: #### 1. **触发时机与作用** - **触发时机**:视图控制器完成视图加载后调用(在 `loadView` 方法之后)[^1][^2] - **关键特征**: ```mermaid graph LR A[initWithNibName] --> B[loadView] B --> C[viewDidLoad] C --> D[viewWillAppear] ``` - **作用**: - 执行**一次性初始化**操作 - 配置视图元素属性(颜色、字体等) - 加载初始数据 - 注册通知/委托 #### 2. **正确使用场景** ```objective-c - (void)viewDidLoad { [super viewDidLoad]; // ✅ 正确场景1:配置视图属性 self.titleLabel.textColor = [UIColor redColor]; self.tableView.delegate = self; // ✅ 正确场景2:初始化数据 [self loadInitialData]; // ✅ 正确场景3:添加手势识别 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)]; [self.view addGestureRecognizer:tap]; // ✅ 正确场景4:注册通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; } ``` #### 3. **禁止操作与常见误区** - ❌ **禁止创建视图**: ```objective-c // 错误示例:创建新视图 UIView *newView = [[UIView alloc] init]; // 应在loadView中创建[^1] ``` - ❌ **避免布局操作**: ```objective-c // 错误示例:设置视图尺寸 self.button.frame = CGRectMake(0, 0, 100, 40); // 应在viewDidLayoutSubviews中处理[^2] ``` - ⚠️ **注意点**: - 每个视图控制器**仅调用一次**(除非手动释放视图) - 视图的几何属性(frame/bounds)尚未确定 - 不保证网络请求完成时界面已显示 #### 4. **与其他生命周期方法对比** | 方法 | 调用次数 | 典型用途 | 视图几何状态 | |---------------------|----------|-----------------------------------|--------------------| | `loadView` | 1次 | 创建视图层次 | 未设置 | | **`viewDidLoad`** | 1次 | 配置视图属性/加载数据 | 未确定 | | `viewWillAppear` | 多次 | 刷新数据/准备动画 | 已确定 | | `viewDidLayoutSubviews` | 多次 | 最终布局调整 | 最终确定 | #### 5. **最佳实践建议** 1. **保持轻量化**: ```objective-c // 耗时操作异步执行 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *data = [NSData dataWithContentsOfURL:imageURL]; dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = [UIImage imageWithData:data]; }); }); ``` 2. **内存管理**: ```objective-c - (void)dealloc { // 必须移除观察者 [[NSNotificationCenter defaultCenter] removeObserver:self]; } ``` 3. **状态恢复**: ```objective-c - (void)encodeRestorableStateWithCoder:(NSCoder *)coder { [super encodeRestorableStateWithCoder:coder]; [coder encodeObject:self.dataArray forKey:@"data"]; } ``` #### 6. **调试技巧** ```objective-c - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"%@: viewDidLoad", self.class); // 检查视图层次 NSLog(@"View hierarchy: %@", self.view.subviews); } ``` > **关键总结**:`viewDidLoad` 是视图初始化的**核心枢纽**,适合执行**一次性配置**,但需避免视图创建和布局操作。它确保视图层次已加载,但尚未显示到屏幕[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值