loadView、viewDidLoad及viewDidUnload的关系

本文详细解析了UIViewController中loadView、viewDidLoad与viewDidUnload三个关键方法的功能与调用时机,帮助开发者更好地理解并掌握视图的生命周期管理。

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

由于本人没有博客园的账号,看到这篇文章很好,转载到csdn上,特此声明!

转载自:http://www.cnblogs.com/mjios/archive/2013/02/26/2933667.html

loadView、viewDidLoad及viewDidUnload的关系

标题中所说的3个方法,都是UIViewController的方法,跟UIViewController的view属性的生命周期息息相关。接下来我会一一阐述它们的作用以及它们之间的联系。

一、loadView

1.什么时候被调用?

每次访问UIViewController的view(比如controller.view、self.view)而且view为nil,loadView方法就会被调用。

2.有什么作用?

loadView方法是用来负责创建UIViewController的view

3.默认实现是怎样的?

默认实现即[super loadView]里面做了什么事情。

1> 它会先去查找与UIViewController相关联的xib文件,通过加载xib文件来创建UIViewController的view

  • 如果在初始化UIViewController指定了xib文件名,就会根据传入的xib文件名加载对应的xib文
[[MJViewController alloc] initWithNibName:@"MJViewController" bundle:nil];
  • 如果没有明显地传xib文件名,就会加载跟UIViewController同名的xib文件
[[MJViewController alloc] init]; // 加载MJViewController.xib

2> 如果没有找到相关联的xib文件,就会创建一个空白的UIView,然后赋值给UIViewController的view属性,大致如下

self.view = [[[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame] autorelease];
// applicationFrame的值是:{{x = 0, y = 20}, {width = 320, height = 460}}

[super loadView]里面就大致完成1>和2>中叙述的内容

4.怎样正确使用这个方法?

大家都知道UIViewController的view可以通过xib文件来创建,但是在某些情况下,xib不是那么地灵活,所以有时候我们想通过代码来创建UIView,比如:

self.view = [[[UIWebView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame] autorelease];

 如果想通过代码来创建UIViewController的view,就要重写loadView方法,并且不需要调用[super loadView],因为在第3点里面已经提到:若没有xib文件,[super loadView]默认会创建一个空白的UIView。我们既然要通过代码来自定义UIView,那么就没必要事先创建一个空白的UIView,以节省不必要的开销。正确的做法应该是这样:

1 - (void)loadView {
2     self.view = [[[UIWebView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame] autorelease];
3 }

不需要调用[super loadView],你调用了也不会出错,只是造成了一些不必要的开销。

总结一句话,苹果设计这个方法就是给我们自定义UIViewController的view用

 

二、viewDidLoad

1.什么时候被调用?

无论你是通过xib文件还是重写loadView方法创建UIViewController的view,在view创建完毕后,最终都会调用viewDidLoad方法

2.有什么作用?

一般我们会在这里做界面上的初始化操作,比如往view中添加一些子视图、从数据库或者网络加载模型数据装配到子视图中。例如:

复制代码
1 - (void)viewDidLoad
2 {
3     [super viewDidLoad];
4     
5     // 添加一个按钮
6     UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
7     [button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
8     [self.view addSubview:button];
9 }
复制代码

 

三、viewDidUnload

1.什么时候被调用?

iOS设备的内存是极其有限的,如果应用程序占用的内存过多的话,系统就会对应用程序发出内存警告。UIViewController就会收到didReceiveMemoryWarning消息。didReceiveMemoryWarning方法的默认实现是:如果当前UIViewController的view不在应用程序的视图层次结构(View Hierarchy)中,即view的superview为nil的时候,就会将view释放,并且调用viewDidUnload方法

2.有什么作用?

上面说到,发出内存警告且view被释放的时候就会调用viewDidUnload方法,所以一般在释放资源,主要是释放界面元素相关的资源,将相关的实例都赋值为nil

1 - (void)viewDidUnload {
2     [super viewDidUnload];
3     self.name = nil;
4     self.pwd = nil;
5 }

3.dealloc也是用来释放资源的,那跟viewDidUnload有什么关系?

当发出内存警告调用viewDidUnload方法时,只是释放了view,并没有释放UIViewController,所以并不会调用dealloc方法。即viewDidUnload和dealloc方法并没有任何关系,dealloc方法只会在UIViewController被释放的时候调用

 

四、三个方法的关系

1.第一次访问UIViewController的view时,view为nil,然后就会调用loadView方法创建view

2.view创建完毕后会调用viewDidLoad方法进行界面元素的初始化

3.当内存警告时,系统可能会释放UIViewController的view,将view赋值为nil,并且调用viewDidUnload方法

4.当再次访问UIViewController的view时,view已经在3中被赋值为nil,所以又会调用loadView方法重新创建view

5.view被重新创建完毕后,还是会调用viewDidLoad方法进行界面元素的初始化


<think>我们正在讨论iOS开发中UIViewController的viewDidLoad方法。根据引用[1]和引用[2],viewDidLoad是UIViewController生命周期中的一个重要方法。 引用[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、付费专栏及课程。

余额充值