MST

星途 面试题库

面试题:Objective-C中视图控制器转换时如何处理内存管理问题

在使用Objective-C进行视图控制器转换(如push、present等)的过程中,经常会遇到内存管理问题。请详细阐述在这些转换操作时,系统默认的内存管理机制,以及如何避免内存泄漏或过度释放的情况。同时,举例说明在自定义视图控制器转换动画时,可能出现的内存管理风险点及解决方案。
12.0万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

系统默认内存管理机制

  1. ARC(自动引用计数):在ARC模式下,编译器会自动为对象的生命周期管理插入引用计数相关的代码。例如,当一个视图控制器被创建时,其引用计数为1。当通过pushpresent操作将其展示在屏幕上时,相关对象(如导航控制器对被push的视图控制器的引用,或者presentingViewController对被presentedViewController的引用)会使该视图控制器的引用计数增加。当视图控制器被popdismiss时,相关引用被移除,引用计数减少。当引用计数变为0时,对象被自动释放。
  2. MRC(手动引用计数):在MRC模式下,开发者需要手动管理对象的引用计数。使用retain方法增加引用计数,使用release方法减少引用计数,autorelease方法会将对象添加到自动释放池,在自动释放池被销毁时减少对象的引用计数。例如,在push一个视图控制器时,开发者需确保在合适的时机手动管理其引用计数,避免过早或过晚释放。

避免内存泄漏或过度释放的方法

  1. ARC下的注意事项
    • 强引用循环:避免在视图控制器之间创建强引用循环。例如,不要在父视图控制器中对一个子视图控制器进行强引用,同时子视图控制器又对父视图控制器进行强引用。可以使用weak关键字来打破这种循环引用。比如,在自定义的容器视图控制器中,如果子视图控制器需要引用父视图控制器,可以将这个引用声明为weak
@property (nonatomic, weak) ParentViewController *parentVC;
  • 代理模式:在使用代理模式时,代理属性应声明为weak,以防止循环引用。例如,一个视图控制器遵守某个协议并作为另一个视图控制器的代理,应这样声明代理属性:
@property (nonatomic, weak) id<SomeProtocol> delegate;
  1. MRC下的注意事项
    • 正确的引用计数操作:确保在合适的时机调用retainreleaseautorelease方法。例如,在创建一个视图控制器对象后,如果要将其传递给其他对象(如导航控制器进行push操作),要注意对象的所有权转移,确保不会过度释放。
    • 自动释放池的使用:合理使用自动释放池,特别是在循环中创建大量临时对象时。例如:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (int i = 0; i < 1000; i++) {
    MyViewController *vc = [[MyViewController alloc] init];
    // 对vc进行操作
    [vc autorelease];
}
[pool drain];

自定义视图控制器转换动画时的内存管理风险点及解决方案

  1. 风险点
    • 动画相关对象的强引用循环:当自定义动画时,可能会在动画对象和视图控制器之间创建强引用循环。例如,在自定义过渡动画代理类中,如果对视图控制器进行了强引用,同时视图控制器又对这个代理类进行强引用,就会导致内存泄漏。
    • 过渡完成后未清理资源:在自定义动画完成后,如果没有正确地释放或移除在动画过程中创建的临时对象(如自定义的过渡视图),可能会导致内存泄漏。
  2. 解决方案
    • 打破强引用循环:在自定义过渡动画代理类中,对视图控制器的引用应声明为weak。例如:
@property (nonatomic, weak) UIViewController *viewController;
  • 清理过渡资源:在过渡动画完成的回调方法中,确保清理所有在动画过程中创建的临时对象。例如,如果在自定义过渡中创建了一个过渡视图,在动画完成后应将其从父视图中移除并释放相关资源:
- (void)animationEnded:(BOOL)transitionCompleted {
    [self.transitionView removeFromSuperview];
    self.transitionView = nil;
}