概述
一般在使用Block时,为了防止循环引用,会使用__weak
,因此下面主要验证下是否在Block中必须使用__weak
验证
- 新建一个类
Car
上面代码主要是//Car.h #import <Foundation/Foundation.h> extern NSString *const CarNotificationName; typedef void(^SomeBlock)(void); @interface Car : NSObject @property (nonatomic, strong) SomeBlock myBlock; - (void)doWithBlock:(SomeBlock)block; - (void)carRunning; @end #import "Car.h" NSString *const CarNotificationName = @"carNotification"; @implementation Car - (Car *)init { self = [super init]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification) name:CarNotificationName object:nil]; } return self; } - (void)receiveNotification { NSLog(@"Receiving Notification"); } - (void)carRunning { } - (void)doWithBlock:(SomeBlock)block { self.myBlock = block; self.myBlock(); } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; NSLog(@"dealloc"); } @end
- 新建
Car
类,只要Car
类实例没有被销毁,就会处理CarNotificationName
的通知 - 方法
- (void)doWithBlock:(SomeBlock)block;
接收一个SomeBlock
类型的参数,并被赋值给一个strong
类型的属性。 - 方法
- (void)dealloc;
注销通知,并打印信息
- 新建
- 现在开始使用
Car
类Car *car = [[Car alloc] init]; [[NSNotificationCenter defaultCenter] postNotificationName:CarNotificationName object:nil]; [car doWithBlock:^{ }]; car = nil; dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5); dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:CarNotificationName object:nil]; });
- 首先获取
Car
类实例 - 紧接着发送
CarNotificationName
通知,此时Car
类实例会收到通知,并在控制台输出信息 - 然后调用
[car doWithBlock:^{}];
方法,传入的block中什么不做,然后将Car
类实例设为nil
,这时Car
类实例被销毁了 - 然后使用
dispatch_after
在5秒后发送CarNotificationName
通知,此时由于Car
类实例被销毁了,因此控制台不会有信息打印出来
- 首先获取
- 如果此时对上面代码做如下改动
发现即使将[car doWithBlock:^{ [car carRunning]; }];
Car
类实例设为nil
,5秒后Car
类实例依然能够接收CarNotificationName
通知,并在控制台打印了对应的信息,也就是Car
类实例并没有被销毁 - 原因就是循环引用产生
Car
类中对SomeBlock
是一个强引用
而在步骤3中的改动代码中,在SomeBlock中反过来对@property (nonatomic, strong) SomeBlock myBlock;
Car
类实例也进行了强引用,这就构成了一个环,导致它们两个不能被销毁。
解决方案
只要将上述的引用环断开其中的一个就可以了,因此有两种解决方法
- 在Block中使用
__weak
Car * __weak weakCar = car; [car doWithBlock:^{ [weakCar carRunning]; }];
-
Car
类中对SomeBlock
弱引用@property (nonatomic, weak) SomeBlock myBlock;
结论
因此,可以确定不是在所有的Block中都要使用__weak
,如果没有构成循环引用,或者对Block是弱引用就可以不必使用__weak
例如GCD或者[UIView animateWithDuration:5.0 animations:^{ }];
中没有构成循环引用,就不必使用__weak
,而在另一些情况如上述步骤3就需要使用__weak
了。
备注
文中测试代码已经上到GitHub
网友评论