一般书上介绍block,都是说block是一个闭包,搞不懂什么是闭包,当做这是一个名词就好。
本文介绍一下block的以下几个方面:
1.block是什么?
2.block的用法
3.栈block 堆block 全局block
1.block是什么
block使用起来像是一个函数指针,但实际在内存中的存储结构像是一个类。
block的内存模型如下:
Class 指针 | isa |
函数指针 | fun |
变量池 |
上面表格中,isa指针指向的就是类的具体类型指针。函数指针fun就是block的执行函数。变量池中保存的都是block函数中所用到的变量的指针地址,例如block函数体中调用了self得某个方法,则变量池中就是保存指向self的指针。
这个内存模型和常规的对象模型又不太一样,所以我将block理解成为只含有一个方法的对象,切对象中得变量是动态增加,减少的。
block在程序中作用非常大,一般我在编程用得最多的就是在http请求中,因为网络请求是一个异步执行的过程,当网络请求成功(失败)时,就会调用相应的block函数。
2.block的用法
returnType (^blockName)(parameter){}
例:
一般用法:
//定义一个block
int (^max)(int a,int b);
//给这个block赋值
max = ^(int a,int b){
return a>b?a:b;
}
//使用block
int m = max(3,5) //m=5
如果需要在block内改变外部变量的数值,则外部变量必须在定义时,前面加上__block关键字
__block int amount = 0;
void (^addAmount) = ^{
amount += 1;
}
NSLog(%d,amount) //amount = 1;
//如果不加__block关键字,则数值在block内无法改变
常规用法:
将block应用在某一函数中,我平时最常用的是网络请求,请求成功,失败都可以用block来实现回调
//用typedef定义两个block
typedef void(^completeSuccess)(id responseObject);
typedef void(^completeFailure)(NSError *error);
..........
//定义类中的方法
void getToken:(completeSuccess) success error:(completeFailure)error;
//如果返回成功,可以用success来存储服务器返回的报文,失败则用error来保存错误报文。
注意事项:
因为Block中会持有变量,这样就有可能在block内引起双向引用。
//在block内调用self方法
void (^someBlock) = ^{
[self someMessage];
}
//以上可能会引起双向引用,self内有block指针,block内持有self指针(保存在常量池中)。
//正确的用法是
__weak id weakSelf = self;
void (^someBlock) = ^{
[weakSelf someMessage];
}
3.栈block,堆block和全局block
//定义一个block
void (^outPut)(void);
if(...){
outPut = ^{
NSLog("output one!");
}
}
else{
outPut = ^{
NSLog("output two!");
}
}
outPut = [^{
NSLog("outPut one");
} copy];
2)全局block
如果有任何问题欢迎再下面留言,或者扫描二维码