一、简述
block 分类: NSGlobalBlock
、NSMallocBlock
和NSstackBlock
,通过内存的分部部局来分类。
block就是保存一段代码块,想用的时候随时调用。
block 特性:自动捕获变量
因为ARC下,系统会自动的对block进行copy操作,所以在MRC下测试
MRC下测试代码
//NSGlobalBlock 全局静态block,没访问外部局部变量,没copy
void(^globalBlock1)(void)= ^{
NSLog(@"TestBlock");
};
NSLog(@"globalBlock1 = %@",globalBlock1);
//NSGlobalBlock 全局静态block,没访问外部变量
void(^globalBlock2)(void) = [^{
NSLog(@"TestBlock");
} copy];
NSLog(@"globalBlock2 = %@",globalBlock2);
///
输出
globalBlock1 = <__NSGlobalBlock__: 0x100c060c0>
globalBlock2 = <__NSGlobalBlock__: 0x100c060e0>
////////////////////////////////////////////////////////////////////////////////////////
int a = 10;
//NSStackBlock ,引用外部变量,没有copy,保存在栈中的block,出函数作用销毁
void(^stackBlock)(void) = ^{
NSLog(@"TestBlock %d",a);
};
NSLog(@"stackBlock = %@",stackBlock);
///
输出
stackBlock = <__NSStackBlock__: 0x16f6974e8>
////////////////////////////////////////////////////////////////////////////////////////
//NSMallocBlock 引用外部变量,copy之后,保存在堆中的block,当引用计数为0时被销毁。
void(^mallocBlock)(void) = [^{
NSLog(@"TestBlock %d",a);
} copy];
NSLog(@"mallocBlock = %@",mallocBlock);
///输出
mallocBlock = <__NSMallocBlock__: 0x11f163200>
那ARC下是不是就只有NSMallocBlock
、NSGlobalBlock
,没有NSstackBlock
了呢,也不是。
ARC下NSstackBlock
测试代码
int a = 10;
__weak void(^weakBlock)(void) = ^{
NSLog(@"weakBlock a = %d",a);
};
NSLog(@"weakBlock%@",weakBlock);
///输出
weakBlock<__NSStackBlock__: 0x16bbf74f8>
二、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拷贝到堆区中,只要对象不销毁,就可以一直调用。