Block笔记(六)

2018-10-30  本文已影响0人  MichealXXX
Block循环引用

如果在block中使用附有__strong修饰符的对象类型自动变量,那么当Block从栈复制到堆时,该对象为Block所持有,这样容易引起循环引用

我们来看一下以下源码:

MyObject.h文件

#import <Foundation/Foundation.h>

typedef void(^blk_t)(NSString *myString);

@interface MyObject : NSObject

@property (nonatomic, copy)blk_t myBlock;

- (void)testBlock;

@end

MyObject.m文件

#import "MyObject.h"

@implementation MyObject

- (void)testBlock{
    self.myBlock(@"this is my block");
}

@end

Viewcontroller.m文件

#import "ViewController.h"
#import "MyObject.h"
@interface ViewController ()

@property(nonatomic,strong)NSString *vcString;

@property(nonatomic,strong)MyObject *obj;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.
    self.obj = [[MyObject alloc] init];
    self.obj.myBlock = ^(NSString *myString) {
        self.vcString = myString;
        NSLog(@"%@",self.vcString);
    };
    
    [self.obj testBlock];
}

我们首先创建了一个MyObject文件,在其.h文件中定义一个Block类型的属性,定义一个方法用于执行Block。然后我们在ViewController.m中使用这个MyObject类,在@interface部分定义一个NSString类型的字符串,以及MyObject类型对象obj。在viewDidLoad方法中初始化对象obj,并且为objBlock属性变量赋值,在Block语法内为ViewController定义的字符串赋值,最后执行obj对象的方法。

其结果正常执行,为NSString类型字符串赋值成功。

2018-10-30 21:40:37.271396+0800 test[4715:412296] this is my block

但是会有警告出现:

Capturing 'self' strongly in this block is likely to lead to a retain cycle

警告告诉我们这里可能会造成循环引用,那么造成的原因是什么呢?

首先我们在MyObject.h文件中定义了一个Block类型属性,也就是说MyObject类对象持有Block,我们又将MyObject对象定义在ViewController.m文件中的@interface区域,这时就相当于ViewController持有MyObject,当Block语法内使用self.vcString,并且由于Block语法赋值给了Block类型属性,因此通过Block语法生成在上的Block会复制到,并持有所使用的self,也就是像下面这种逻辑。

self->MyObject->Block->self

在之前的内存管理中说过,当两个对象互相持有对方强引用将会造成在作用域结束之后对象不能被正确释放,这就是循环引用

在内存管理中说道__weak修饰符可以解决循环引用的问题,在这里其实也是通过__weak修饰符解决,只不过方法不太一样,我们还是用上面的源码举例,只不过做一点点改变:

#import "ViewController.h"
#import "MyObject.h"
@interface ViewController ()

@property(nonatomic,strong)NSString *vcString;

@property(nonatomic,strong)MyObject *obj;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    self.obj = [[MyObject alloc] init];
    self.obj.myBlock = ^(NSString *myString) {
        weakSelf.vcString = myString;
        NSLog(@"%@",weakSelf.vcString);
    };
    
    [self.obj testBlock];
}

可以看到这一段代码

__weak typeof(self) weakSelf = self;

self赋值给附有__weak修饰符的变量weakSelf,在Block语法中使用weakSelf,这样Block就不能持有self的强引用,也就打破了循环使用。

self->MyObject->Block --- self

总而言之,当我们在Block中使用self时,一定要注意是否会造成循环引用,根据情况添加__weak typeof(self) weakSelf

上一篇 下一篇

猜你喜欢

热点阅读