block的分类
- 全局
__NSGlobalBlock__
- 栈
- 堆
// <__NSGlobalBlock__: 0x100128240>
// 没有使用外部变量
NSLog(@"%@", ^(){
NSLog(@"hello world");
});
// 使用静态变量
static int age = 100;
NSLog(@"%@", ^(){
NSLog(@"age is %d", age);
});
// 使用全局变量 写在函数外面
// int pai = 31.4;
// - (void)viewDidLoad {
NSLog(@"%@", ^(){
NSLog(@"pai is %d", pai);
});
//__NSMallocBlock__
int a = 10;
void (^ m) (void) = ^ (void){
NSLog(@"a is %d",a );
};
NSLog(@"%@", m);
//__NSStackBlock__
int a = 10;
void (^ __weak hello) (void) = ^ (void){
NSLog(@"a is %d",a );
};
NSLog(@"%@", hello);
copy
因为默认的block是栈内存的,当前函数结束就会被销毁。所以我们需要使用copy。属性使用strong也会调用copy。
引用计数
弱引用的block也会捕获外部变量,同时强引用也会再次捕获。因此强引用加2。
// 结果为3和4
NSObject *obj = [NSObject new];
void (^block1)(void) = ^(){
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
};
block1();
void (^__weak block2)(void) = ^(){
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
};
block2();
NSObject *obj = [NSObject new];
void (^block0)(void);
{
void (^block1)(void) = ^(){
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
};
// 由于block1为堆,所以这里不会再次捕获
block0 = block1;
block1();//3
}
//2 此时,没有栈的block
block0();
void (^__weak block2)(void) = ^(){
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
};
// 3 此时又多了一个栈捕获
block2();
循环引用
// 循环引用
// 1 weakSelf不会对self强引用
__weak typeof(self) weakSelf = self;
// 2 weakSelf此时不为nil,因此本质还是让当前对象的block强引用当前对象
weakSelf.block = ^ (){
self.name = @"hello";
};
下面代码中self引用了block。而Block又引用了self,因此会导致循环引用。
@interface SecondViewController ()
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) void (^block)(void);
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
self.block = ^ (){
self.name = @"test";
};
}
改成下面的方式,效果一样,本质还是引用了self.
self.block = ^ (){
_name = @"demo";
};
使用__weak解决循环引用。
__weak typeof(self) weakSelf = self;
self.name = @"test";
self.block = ^ (){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",weakSelf.name);
});
};
self.block();
但是上面的代码会导致weakself为空,所以打印的是null。此时需要再次进行强引用。下面在页面退出的时候。会先等block执行结束再dealloc。
self.view.backgroundColor = [UIColor redColor];
__weak typeof(self) weakSelf = self;
self.name = @"test";
self.block = ^ (){
__strong typeof(self) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf.name);
});
};
self.block();
通过临时变量解决循环引用
这个方法有限制,只能使用一次。
self.name = @"test";
__block
SecondViewController *vc = self;
self.block = ^ (){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",vc.name);
vc = nil;
});
};
self.block();
参数传递解决循环引用
因为block没有引用外部变量。
self.name = @"test";
self.block = ^ (SecondViewController *vc){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",vc.name);
});
};
self.block(self);
static和循环引用
static是全局作用域,赋值的时候会强引用。对弱引用的强引用会导致强引用。
static SecondViewController *a;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
self.name = @"test";
__weak typeof(self) weakSelf = self;
a = weakSelf;
}