block简单来说就是一个回调,用来实现数据的方向传递,延时后的数据传递。
但是block有一个比较让人头疼的地方,就是block内self的使用。
先看一下block内部结构
让我们写一个会循环引用的情况
RokkiaBlockTest.m内
typedef void(^HAHA)(NSInteger a); //定义block
@interface RokkiaBlockTest()
@property(nonatomic, assign)NSInteger inte; //定义block中会用到的参数
@property(nonatomic, copy)HAHA h; //在property中定义block
@end
@implementation RokkiaBlockTest
-(void)blockblockblock{
// __weak __typeof(self) wself = self;
self.h = ^(NSInteger a){
NSLog(@"%ld", a + self.inte);
};
self.h(20);
}
-(void)dealloc{
NSLog(@"程序结束");
}
@end
ViewController.m内
#import "RokkiaBlockTest.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
RokkiaBlockTest *network = [[RokkiaBlockTest alloc]init];
[network blockblockblock];
}
我们运行程序,我们会发现dealloc中的程序结束并没有执行。
原因,我们回到这里
self.h = ^(NSInteger a){ //self持有了block OK block计数器+1
NSLog(@"%ld", a + self.inte); //block内 block持有了self OK self计数器+1
};
self.h(20); //执行,
问题来了因为block与self计数器都 + 1了 当程序结束后 self - 1 block - 1 但是self-1并不等于0 于是self不会被释放 block同理,于是他们互相持有却没有一个可以先释放,于是形成循环引用。
解决方式:
-(void)blockblockblock{
__weak __typeof(self) wself = self; // 在block外对self进行weak操作
self.h = ^(NSInteger a){
NSLog(@"%ld", a + self.inte);
};
self.h(20);
}
问题来了,如果self没有持有block 或者 block没有持有self的情况会怎么样。
改写1
-(void)blockblockblock{
// __weak __typeof(self) wself = self;
self.h = ^(NSInteger a){
NSLog(@"%ld", a); // 去掉self
};
self.h(20);
}
改写2
-(void)blockblockblock{
// __weak __typeof(self) wself = self;
HAHA h = ^(NSInteger a){
NSLog(@"%ld", a);
};
h(20);
}
结果
2018-06-27 13:56:56.634307+0800 RokkiaBlockTest[11935:1371001] 程序结束
这里有另外一个问题了,如果将一个block传入到单例中会怎样。
单例对象 TTest.h中
typedef void(^doSome)(NSInteger a);
@interface test : NSObject
+(nonnull instancetype) sharedManager;
-(void)doSomeWithBlock:(doSome _Nullable )block;
@end
单例对象TTest.m中
@implementation test
+(nonnull instancetype)sharedManager{
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [self new];
});
return instance;
}
-(void)doSomeWithBlock:(doSome)block{
block(20);
}
@end
RokkiaBlockTest.m中
-(void)testtest{
[self dododo];
TTest *t = [TTest sharedManager];
if (self.ds) {
[t doSomeWithBlock:self.ds];
}else{
NSLog(@"没有执行");
}
}
-(void)dododo{
// __weak __typeof(self) wself = self;
self.ds = ^(NSInteger a){
NSLog(@"test %ld",a + self.inte);
};
}
Viewcontroller.m中
[network testtest];
结果
2018-06-27 14:13:41.195511+0800 RokkiaNetWorking[12090:1385836] test 30
我们发现产生了循环引用
解决,跟上面一样 添加 __weak __typeof(self) sweak = self;
跟上面的一样思考, 如果self没有持有block 或者 block没有持有self的情况会怎么样。
改写1
-(void)testtest{
test *t = [test sharedManager];
doSome ds = ^(NSInteger a){
NSLog(@"test %ld",a + self.inte);
};
[t doSomeWithBlock:ds];
}
改写2
-(void)testtest{
[self dododo];
test *t = [test sharedManager];
if (self.ds) {
[t doSomeWithBlock:ds];
}else{
NSLog(@"没有执行");
}
}
-(void)dododo{
// __weak __typeof(self) wself = self;
self.ds = ^(NSInteger a){
NSLog(@"test %ld",a);
};
}
结果
2018-06-27 14:19:17.832694+0800 RokkiaNetWorking[12118:1389889] test 30
2018-06-27 14:19:17.833403+0800 RokkiaNetWorking[12118:1389889] 程序结束