MST

星途 面试题库

面试题:Objective-C中如何优雅地管理视图控制器的生命周期以避免内存泄漏

在iOS开发中,视图控制器的不当管理容易导致内存泄漏。请详细说明在Objective - C语言环境下,如何通过合理管理视图控制器的生命周期(如loadView、viewDidLoad、viewWillAppear、viewDidAppear等方法)来有效避免内存泄漏?如果涉及到视图控制器的嵌套(如导航控制器、标签栏控制器等),又该如何特殊处理?
30.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. 视图控制器生命周期方法与避免内存泄漏

  • loadView
    • 此方法用于创建视图控制器的视图。如果手动创建视图,应避免强引用循环。例如,不要在 loadView 中让视图对视图控制器产生强引用。比如,自定义视图类中不应有类似 @property (nonatomic, strong) MyViewController *viewController; 这样会导致循环引用的属性,并在 loadView 中赋值。
    • 如果从 nib 文件加载视图,确保 nib 文件中的对象关系正确,避免出现强引用循环。
  • viewDidLoad
    • 初始化视图相关的属性和数据。但要注意,对于添加到视图的子视图或设置的代理等,不要形成强引用循环。例如,设置代理时应使用 weakunsafe_unretained(不推荐 unsafe_unretained,有悬空指针风险)。比如,self.tableView.delegate = self; 这里 tableView 不应强引用 self,应确保 tableViewdelegate 属性是 weak 类型。
    • 对于注册的通知,要在视图控制器销毁时移除。例如,[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"SomeNotification" object:nil]; 要在 dealloc 方法中 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"SomeNotification" object:nil];,否则会导致视图控制器无法释放而内存泄漏。
  • viewWillAppear
    • 在这里进行与视图即将显示相关的操作,如更新界面数据等。避免创建不必要的强引用对象,如果创建了临时对象,要确保它们在合适的时候被释放。例如,不要在 viewWillAppear 中创建一个强引用的临时视图并一直持有,导致视图控制器无法释放。
  • viewDidAppear
    • 同样,避免在这里创建可能导致强引用循环或内存泄漏的对象。如果有动画等操作,确保动画完成后相关对象能正确释放。例如,使用 CAAnimation 时,设置 anim.delegate = self; 要在动画结束时清理相关引用,否则可能导致循环引用。

2. 视图控制器嵌套时的特殊处理

  • 导航控制器(UINavigationController)
    • 当视图控制器压入导航控制器栈时,导航控制器会对其产生强引用。确保从导航控制器栈弹出视图控制器时,视图控制器中的资源能正确释放。比如,对于弹出视图控制器时正在进行的网络请求,要取消请求,避免视图控制器无法释放。可以在 viewWillDisappear 方法中取消网络请求,例如使用 AFNetworking 时,[self.dataTask cancel];
    • 不要在导航控制器的子类中对某个视图控制器形成不合理的强引用。例如,导航控制器子类不应有 @property (nonatomic, strong) MyViewController *specificViewController; 并一直持有,导致该视图控制器无法释放。
  • 标签栏控制器(UITabBarController)
    • 标签栏控制器会强引用其包含的视图控制器。当切换标签时,要确保不再显示的视图控制器能正确释放资源。例如,对于视图控制器中的定时器,在 viewWillDisappear 中停止并释放定时器,[self.timer invalidate]; self.timer = nil;
    • 避免在标签栏控制器的子类中对某个子视图控制器形成不合理的强引用,导致子视图控制器无法释放。同时,要注意子视图控制器之间的关系,避免出现循环引用。例如,两个子视图控制器之间互相强引用对方,应使用 weak 引用来打破循环。