面试题答案
一键面试代码块循环引用可能出现的场景
- 对象持有代码块,代码块又强引用对象:当一个对象将代码块作为其属性持有,而在该代码块内部又直接或间接强引用了这个对象本身时,就会出现循环引用。例如,在视图控制器(ViewController)中定义一个属性为代码块,在代码块中访问视图控制器的属性或方法,这就形成了循环引用。
- 代码块内部捕获对象:如果在代码块中使用了某个对象的实例变量、方法等,编译器会自动捕获该对象,若代码块被其他对象持有,而这个对象又持有该代码块,就会出现循环引用。比如在一个自定义视图(CustomView)类中,有一个方法接收一个代码块参数,在这个代码块中访问 CustomView 的实例变量,同时这个代码块被外部对象持有,而外部对象又持有 CustomView,就会产生循环引用。
使用 __weak
关键字避免循环引用
- 原理:
__weak
修饰的变量是弱引用,不会增加对象的引用计数,当对象的强引用计数为 0 时,对象被释放,__weak
修饰的变量会自动被设置为nil
,从而打破循环引用。 - 示例:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
// 在这里可以安全地访问 strongSelf 的属性和方法
strongSelf.title = @"新标题";
}
});
}
@end
在上述代码中,首先使用 __weak
关键字创建了一个对 self
的弱引用 weakSelf
。在代码块内部,为了避免在执行代码块期间 self
被释放,又通过 __strong
关键字将 weakSelf
提升为强引用 strongSelf
,并且通过 if (strongSelf)
判断 self
是否已经被释放,如果没有被释放,就可以安全地访问 self
的属性和方法。这样就避免了代码块对 self
的循环引用。