OC中循环引用和@weakify和@strongify

引自:ObjC的Block中使用weakSelf/strongSelf @weakify/@strongify_objc weak self-优快云博客

Objective C 的 Block 是一个很实用的语法,特别是与GCD结合使用,可以很方便地实现并发、异步任务。但是,如果使用不当,Block 也会引起一些循环引用问题(retain cycle)—— Block 会 retain ‘self’,而 ‘self‘ 又 retain 了 Block。因为在 ObjC 中,直接调用一个实例变量,会被编译器处理成 ‘self->theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1,于是,self retains queue, queue retains block,block retains self。

解决 retain circle

Apple 官方的建议是,传进 Block 之前,把 ‘self’ 转换成 weak automatic 的变量,这样在 Block 中就不会出现对 self 的强引用。如果在 Block 执行完成之前,self 被释放了,weakSelf 也会变为 nil。

示例代码:

__weak __typeof__(self) weakSelf = self;    

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{     [weakSelf doSomething];
 });

clang 的文档表示,在 doSomething 内,weakSelf 不会被释放。但,下面的情况除外:

 __weak __typeof__(self) weakSelf = self;
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     [weakSelf doSomething];
     [weakSelf doOtherThing];
 });

在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:

 __weak __typeof__(self) weakSelf = self;
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     __strong __typeof(self) strongSelf = weakSelf;
     [strongSelf doSomething];
     [strongSelf doOtherThing];
 });

__strong 确保在 Block 内,strongSelf 不会被释放。

总结 
在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。 
如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

使用过RAC的同学应该都知道@weakify和@strongify,这两个宏在RAC中是已经定义好的,可以直接用,属于比较牛逼的写法。这两个宏一定成对出现,先@weakify再@strongify。可以很好的管理Block内部对self的引用。可以一步步点开发现其实使用到了C语言中的组合运算符。

@weakify(self);  
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      @strongify(self);
      [self doSomething];
      [self doOtherThing];
  });

循环引用

例子如下:

BlockPerson.m文件

@interface BlockPerson : NSObject

@property (nonatomic, copy)NSString *string;
@property (nonatomic, copy)void(^myBlock)();

@end

#import "BlockPerson.h"

@implementation BlockPerson

- (void)dealloc
{
    NSLog(@"blockPerson dealloc");
}

@end

ViewController.m文件 

#import "ViewController.h"
#import "BlockPerson.h"

@interface ViewController ()

@property (copy) NSString *myName;
@property (strong,nonatomic) BlockPerson *person;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self blockWeakStrongTest5];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


//1.添加弱引用,解决block内部循环引用
- (void)blockTest1{

    BlockPerson *shop = [[BlockPerson alloc]init];

    __weak  typeof(shop) weakShop = shop;

    shop.string = @"welcome to our company";
    shop.myBlock = ^{
        NSLog(@"%@",weakShop.string);
    };
    shop.myBlock();

}

//2.block不会循环引用
- (void)blockTest2{

    self.myName = @"blockTest2";
    BlockPerson *shop = [[BlockPerson alloc]init];

    shop.string = @"welcome to our company";
    shop.myBlock = ^{
        NSLog(@"%@",self.myName);
    };
    shop.myBlock();

}


//3.block循环引用
- (void)blockTest3{

    self.myName = @"blockTest2";
    self.person = [[BlockPerson alloc]init];

    self.person.string = @"welcome to our company";
    self.person.myBlock = ^{
        NSLog(@"%@",self.myName);
    };
    self.person.myBlock();

}


//4.虽然使用了弱引用,但是GCD延迟调用weakShop,但是此时weakShop已被释放掉,打印出来null
- (void)blockWeakStrongTest4{
    //弱引用
    BlockPerson *shop = [[BlockPerson alloc]init];
    shop.string = @"welcome to our company";
    __weak typeof(shop) weakShop = shop;
    shop.myBlock = ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",weakShop.string);
        });
    };
    shop.myBlock();
}


//5.在block中再使用强引用解决GCD延迟调用weakShop,weakShop已被释放掉的问题,打印出来welcome to our company
- (void)blockWeakStrongTest5{
    //弱引用
    BlockPerson *shop = [[BlockPerson alloc]init];
    shop.string = @"welcome to our company";
    __weak typeof(shop) weakShop = shop;
    shop.myBlock = ^{
        __strong typeof(shop) strongShop = weakShop;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",strongShop.string);
        });
    };
    shop.myBlock();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值