OC中对Block理解

来源:互联网 发布:虚拟软件 编辑:程序博客网 时间:2024/04/30 15:41

一般书上介绍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的用法

   block用法的定义如下:
    
returnType (^blockName)(parameter){}

  例: 

  一般用法:

//定义一个blockint (^max)(int a,int b);//给这个block赋值max = ^(int a,int b){    return a>b?a:b;}//使用blockint 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定义两个blocktypedef 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

1)堆栈block

      看一个例子:
       
//定义一个blockvoid (^outPut)(void);if(...){    outPut = ^{    NSLog("output one!");}    }else{       outPut = ^{      NSLog("output two!");}}

以上这段代码,执行后,会出现有时执行正确,有时执行错误的情况。
这是因为,在if,else中block是分配在栈内存中的,如果编译器将其他代码分配到同一块栈内存时,则block失效。

要解决这个问题,可以在分配时,加上copy关键字,这个时候就能将栈内存中得数据转移到堆内存中,堆内存中的数据,当retainCount为0时,才释放。
outPut = [^{  NSLog("outPut one");} copy];

2)全局block

   


如果有任何问题欢迎再下面留言,或者扫描二维码


0 0