一、简述
block 分类: NSGlobalBlock、NSMallocBlock和NSstackBlock,通过内存的分部部局来分类。
block就是保存一段代码块,想用的时候随时调用。
block 特性:自动捕获变量
//NSGlobalBlock 全局静态block,不会访问外部局部变量
void (^block)(void) = ^{
NSLog(@"hello block");
};
block();
NSLog(@"%@",block);
//NSMallocBlock 堆block 保存在堆中的block,当引用计数为0时被销毁。
int a = 10;
void (^block)(void) = ^{
NSLog(@"hello block - %d",a);
};
block();
NSLog(@"%@",block);
//NSStackBlock 保存在栈中的block,当函数返回时会被销毁。
NSLog(@"%@",^{
NSLog(@"hello block - %d",a);
});
二、block的简单使用
//1、作为对象属性
typedef void(^ Myblock)(void);
@property(nonatomic,strong) Myblock block;
//或
@property(nonatomic,strong) void(^block)(void);
//2、作为方法参数
- (void)btnHandler:(void(^)(void))block
{
block();
}
//3、作为方法返回值。点语法调用、响应式编程
- (void(^)(int))run{
return ^(int m){
NSLog(@"跑起来,跑了%d米",m);
};
}
p.run(3);
三、循环引用解决方式
//方法1
//只加__weak,在VC被释放后,操作有可能无法完成,在内部加上strong后,可保证操作完成,strongSelf是局部变量,在操作完成出了block作用域后,会被释放,不会引起循环引用
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
NSLog(@"%@", strongSelf.title);
};
//方法2
//把self放到局部变量中,self -> block -> vc -> self,在使用完成之后,vc = nil;即可打破循环引用,加__block是为了让vc能在block中被修改。
__block ViewController * vc = self
self.block = ^{
NSLog(@"%@", vc.title);
vc = nil;
};
//方法3
//传参,参数在操作执行完成,出了block作用域之后,会被释放,打破循环引用。
@property (nonatomic, copy) void(^block)(ViewController * vc);
self.block = ^(ViewController * vc){
NSLog(@"%@",vc.name);
};
self.block(self);
四、为什么要给int a加__block,加不加__block有什么区别
1、不加__block,变量a被捕获,为值传递,只读,只可NSLog输出,如果在block内修改a的话,编译器报错。
2、加__block后,是指针传递,可读可写,可对a的值进行修改。
__block int a = 10;
void(^block)(void) = ^{
a++;
};
block();
五、block为什么用copy关键字修饰
在MRC下,引入外部变量的block被存放在栈区,出了作用域会被释放,再次调用会造成崩溃。使用copy可以把block拷贝到堆区中,只要对象不销毁,就可以一直调用。
网友评论