MST

星途 面试题库

面试题:Objective-CARC下潜在内存泄漏场景分析

在ARC(自动引用计数)环境下,Objective-C仍可能存在内存泄漏。请列举至少三种ARC下可能导致内存泄漏的场景,并说明原因以及如何避免这些内存泄漏。
33.2万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试
  1. 循环引用(Retain Cycles)
    • 原因:两个或多个对象之间相互持有强引用,形成一个循环,导致对象无法被释放。例如,一个视图控制器(ViewController)持有一个视图(View),而这个视图又持有视图控制器作为其代理(delegate),如果两者都使用强引用,就会形成循环引用。
    • 避免方法:将其中一个引用改为弱引用(weak)或无主引用(unowned)。在上述例子中,视图的代理属性通常应设置为弱引用,这样当视图控制器被释放时,视图对其的引用不会阻止视图控制器的释放。示例代码如下:
// View.h
@property (nonatomic, weak) id<ViewDelegate> delegate;
  1. NSTimer的强引用
    • 原因:当使用NSTimer并将其添加到运行循环(RunLoop)中时,如果NSTimer持有对某个对象的强引用,而这个对象又持有NSTimer,就会造成循环引用。比如,在视图控制器中创建NSTimer并设置其目标为视图控制器自身,NSTimer会强引用视图控制器,而视图控制器又持有NSTimer,导致视图控制器在deallocNSTimer无法释放,进而视图控制器也无法释放。
    • 避免方法
      • 可以使用weak修饰符来打破循环引用。在视图控制器中创建一个弱引用自身的变量,然后将其作为NSTimer的目标。示例代码如下:
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(updateUI) userInfo:nil repeats:YES];
  - 当视图控制器即将被销毁时,手动使`NSTimer`失效。在视图控制器的`dealloc`方法中调用`[self.timer invalidate]; self.timer = nil;`。

3. Block的循环引用 - 原因:在Block内部使用对象时,如果Block被对象持有,而Block又强引用对象,就会形成循环引用。例如,在视图控制器中定义一个Block,在Block内部访问视图控制器的属性,而这个Block又被视图控制器持有,就会造成循环引用。 - 避免方法: - 使用__weak修饰符创建一个弱引用对象,在Block内部使用弱引用对象。示例代码如下:

__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
    NSLog(@"%@", weakSelf.title);
};
  - 在Block内部先将弱引用对象赋给一个强引用对象,以防止在Block执行期间对象被释放。示例代码如下:
__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        NSLog(@"%@", strongSelf.title);
    }
};
  1. Core Foundation对象的手动内存管理
    • 原因:虽然ARC负责Objective - C对象的内存管理,但对于Core Foundation对象(如CFStringRefCFArrayRef等),需要手动调用相应的内存管理函数(如CFRelease)。如果在ARC环境下使用Core Foundation对象,却忘记调用CFRelease,就会导致内存泄漏。
    • 避免方法:使用桥接转换(bridging casts)将Core Foundation对象转换为Objective - C对象,这样ARC就能管理其内存。例如,将CFStringRef转换为NSString *
CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "Hello", kCFStringEncodingUTF8);
NSString *nsString = (__bridge_transfer NSString *)cfString;
// 此时nsString由ARC管理,无需手动调用CFRelease
  1. 集合类中对象的内存管理
    • 原因:当向集合类(如NSArrayNSDictionaryNSSet)中添加对象时,如果添加的对象在集合类外部被意外释放,而集合类仍持有该对象的强引用,可能会导致悬空指针(dangling pointer)问题,并且当集合类本身被释放时,该对象也不会被正确释放,造成内存泄漏。
    • 避免方法:确保添加到集合类中的对象在整个生命周期内都能被正确管理。如果需要从集合类中移除对象,在移除后确保对象在其他地方有合理的内存管理。例如,在从数组中移除对象后,检查该对象是否还被其他地方使用,若不再使用,可以设置为nil以确保其被释放。示例代码如下:
NSMutableArray *array = [NSMutableArray arrayWithObject:self.someObject];
[self.someObject doSomething];
[self.array removeObject:self.someObject];
self.someObject = nil;