需要在block中 使用self时一定要注意是否会发生循环引用的问题。
在我们平时将block定义为属性的时候,我们都是使用copy,在这里先记住这个用法,以后在讨论为什么block要使用copy
现在我们要讨论的block导致的循环引用,以及该如何解决循环引用
-->表示强引用
--表示弱引用
造成了循环引用无法释放
分析代码中的强引用得出下面的情况
self-->tool-->finishedCallBack(NetworkTools的属性)-->finishedCallBack(传进来的代码块)-->self
解决循环引用的原则:打破任意一个 强引用即可
现在我们来介绍三种用来解决循环引用的方式
1.weak-strong dance 这是在苹果2011年WWDC会议上一个的session,
这种解除循环引用的方式在AFNetworking框架中广泛使用,我们在工作中也应该广泛的使用这种方式.
self-->tool-->finishedCallBack(NetworkTools的属性)-->finishedCallBack(传进来的代码块)-->strongSelf-->weakSelf--self
weakSelf对self是弱引用,打破了循环强引用。
2. __weak typeof(self) weakSelf = self;这也是我最初接触的到的解决循环强引用的方式,
typeof(self)获取self的类型 weakSelf弱引用self
__weak是在IOS 5.0之后出现的,同事还推出了storyboard和arc。
这个__weak和 weak属性关键字作用类似,当对象被系统回收的时候,内存地址会自动指向nil,此时如果再次
向这个对象发送消息,不会崩溃。
self-->tool-->finishedCallBack(NetworkTools的属性)-->finishedCallBack(传进来的代码块)-->strongSelf-->weakSelf--self
weakSelf对self是弱引用,打破了循环强引用。
3. __unsafe_unretained typeof(self) weakSelf = self;这是一种比较久远的解决循环强引用的方式。
这是在iOS 4.0时出现的,这个方案并不好,因为这个__unsafe_unretained和assign属性关键字类似,
当对象被系统回收的时候,内存地址不变,不会自动指向nil.如果这个时候意外使用了weakSelf,将会导致程序
崩溃,EXC_BAD_ACCESS野指针问题,MRC年代最常见的错误之一。
4.在MRC环境下,其实解决方法与ARC环境下差不多,只不过是将__weak typeof(self) weakSelf = self
变成__block typeof(self) weakSelf = self;告诉编译器我这里是block,不要再将retain做加1操作了。
//现在只是一部分代码,无法直接运行,源代码下载地址
----------------------------------------------------------------------------------------------------------------
#import "ViewController.h"
#import "NetworkTools.h"
@interface ViewController ()
@property(nonatomic, strong) NetworkTools *tools;
@end
@implementation ViewController
-(void)viewDidLoad{
[super viewDidLoad];
[self solve1];
}
//解决循环强引用的第一种方式
-(void) solve1{
self.tools = [[NetworkTools alloc] init];
__weak typeof(self) weakSelf = self;
[self.tools loadData:^(NSString *result) {
__strong typeof(weakSelf)strongSelf = weakSelf;
NSLog(@"完成回掉%@%@",result,strongSelf.view);
}];
}
//解决循环强引用的第二种方式
-(void) solve2{
self.tools = [[NetworkTools alloc] init];
__weak typeof(self) weakSelf = self;
[self.tools loadData:^(NSString *result) {
NSLog(@"完成回掉%@%@",result,weakSelf.view);
}];
}
//解决循环强引用的第三种方式
-(void) solve3{
self.tools = [[NetworkTools alloc] init];
__unsafe_unretained typeof(self) weakSelf = self;
[self.tools loadData:^(NSString *result) {
NSLog(@"完成回掉%@%@",result,weakSelf.view);
}];
}
//循环强引用,导致内存泄露
- (void) method1 {
self.tools = [[NetworkTools alloc] init];
[self.tools loadData:^(NSString *result) {
NSLog(@"完成回掉%@%@",result,self.view);
}];
}
- (void)dealloc
{
NSLog(@"VC 被释放了");
}
@end
-------------------------------------------------------------------------------------------------------------------
#import "NetworkTools.h"
@interface NetworkTools ()
//用来记录函数参数的属性block
@property(nonatomic,copy) void(^finishedCallBack)(NSString *);
@end
@implementation NetworkTools
//加载数据
- (void)loadData:(void (^)(NSString *))finishedBlock {
self.finishedCallBack = finishedBlock;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//异步耗时任务
[NSThread sleepForTimeInterval:3];
//请求成功 需要在主队列回调
dispatch_async(dispatch_get_main_queue(), ^{
// finishedBlock();
[self dataTOJSONDict:@"01010101010101101010101010"];
});
});
}
//反序列化的方法
- (void) dataTOJSONDict:(NSString* )data {
if (self.finishedCallBack) {
self.finishedCallBack(@"回调被调用了");
}
}
- (void)dealloc
{
NSLog(@"Tool 被释放了");
}
@end