MST

星途 面试题库

面试题:Objective-C中Block导致内存循环引用在MRC环境下的解决方案

在MRC(手动引用计数)环境下,Objective-C中Block导致内存循环引用通常有哪些解决方案?请简要说明每种方案的原理及实现方式。
39.4万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

方案一:使用__block修饰符

  • 原理:__block修饰符修饰的变量,其内存管理方式会有所改变。在Block内部对其引用时,不会增加其引用计数,从而打破循环引用。
  • 实现方式:在声明变量时使用__block修饰,例如:
__block id obj = [[NSObject alloc] init];
void (^block)(void) = ^{
    NSLog(@"%@", obj);
};
block();

方案二:使用__weak(ARC环境下)或__unsafe_unretained(MRC环境下)修饰符

  • 原理:__weak(ARC)或__unsafe_unretained(MRC)修饰的变量,在被Block引用时,不会增加其引用计数。__weak在对象释放时会自动将指针置为nil,而__unsafe_unretained不会自动置nil,使用时需注意野指针问题。
  • 实现方式
// MRC环境下
__unsafe_unretained id obj = [[NSObject alloc] init];
void (^block)(void) = ^{
    NSLog(@"%@", obj);
};
block();
[obj release];

// ARC环境下类似,只是将__unsafe_unretained换成__weak
__weak id obj = [[NSObject alloc] init];
void (^block)(void) = ^{
    NSLog(@"%@", obj);
};
block();

方案三:在Block执行完毕后手动断开循环引用

  • 原理:在Block执行完后,手动将Block或Block内部强引用的对象设置为nil,从而打破循环引用。
  • 实现方式
id obj = [[NSObject alloc] init];
__block void (^block)(void);
block = ^{
    NSLog(@"%@", obj);
    block = nil; // 执行完Block后将其设为nil
};
block();
[obj release];