block导致的循环引用问题的分析基解决办法

 需要在block 使用self时一定要注意是否会发生循环引用的问题。


 在我们平时将block定义为属性的时候,我们都是使用copy,在这里先记住这个用法,以后在讨论为什么block要使用copy

 现在我们要讨论的block导致的循环引用,以及该如何解决循环引用

 

 -->表示强引用

 --表示弱引用

 

 造成了循环引用无法释放

 分析代码中的强引用得出下面的情况

 self-->tool-->finishedCallBack(NetworkTools的属性)-->finishedCallBack(传进来的代码块)-->self

 

 解决循环引用的原则:打破任意一个 强引用即可

 

 现在我们来介绍三种用来解决循环引用的方式

 1.weak-strong dance 这是在苹果2011WWDC会议上一个的session,

 这种解除循环引用的方式在AFNetworking框架中广泛使用,我们在工作中也应该广泛的使用这种方式.

 

 self-->tool-->finishedCallBack(NetworkTools的属性)-->finishedCallBack(传进来的代码块)-->strongSelf-->weakSelf--self

 weakSelfself是弱引用,打破了循环强引用。

 

 2. __weak typeof(self) weakSelf = self;这也是我最初接触的到的解决循环强引用的方式,

 typeof(self)获取self的类型  weakSelf弱引用self

 

 __weak是在IOS 5.0之后出现的,同事还推出了storyboardarc

 这个__weak weak属性关键字作用类似,当对象被系统回收的时候,内存地址会自动指向nil,此时如果再次

 向这个对象发送消息,不会崩溃。

 

 self-->tool-->finishedCallBack(NetworkTools的属性)-->finishedCallBack(传进来的代码块)-->strongSelf-->weakSelf--self

 weakSelfself是弱引用,打破了循环强引用。

 

 

 3. __unsafe_unretained typeof(self) weakSelf = self;这是一种比较久远的解决循环强引用的方式。

 这是在iOS 4.0时出现的,这个方案并不好,因为这个__unsafe_unretainedassign属性关键字类似,

 当对象被系统回收的时候,内存地址不变,不会自动指向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


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

你可能感兴趣的:(Objective-C)