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
,并且为obj
的Block
属性变量赋值,在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
。
网友评论