Block

一、概述

Block是C级别的语法和运行时特性。Block比较类似C函数,但是Block比之C函数,其灵活性体现在栈内存、堆内存的引用,我们甚至可以将一个Block作为参数传给其他的函数或者Block。

 block的几种应用场合:

  1.  任务完成时回调处理
  2.  消息监听回调处理
  3.  错误回调处理
  4.  枚举回调
  5.   视图动画、变换
  6.   排序


二、block放在哪里

               

         在Objective-C语言中,一共有3种类型的block:
           1)_NSConcreteGlobalBlock 全局的静态block,不会访问任何外部变量。
           2)_NSConcreteStackBlock 保存在栈中的block,当函数返回时会被销毁。
           3)_NSConcreteMallocBlock 保存在堆中的block,当引用计数为0时会被销毁。

我们针对不同情况来讨论block的存放位置:

1.栈和堆

以下情况中的block位于堆中:

    
  1. void foo()  
  2. {  
  3.     __block int i = 1024;  
  4.     int j = 1;  
  5.     void (^blk)(void);  
  6.     void (^blkInHeap)(void);  
  7.     blk = ^{ printf("%d, %d\n", i, j);};//blk在栈里  
  8.     blkInHeap = Block_copy(blk);//blkInHeap在堆里  
  9. }  
  10.    
  11. - (void)fooBar  
  12. {  
  13.     _oi = 1;  
  14.     OBJ1* oj = self;  
  15.     void (^oblk)(void) = ^{ printf("%d\n", oj.oi);};  
  16.     void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中  

2.全局区

以下情况中的block位于全局区:

  1. static int(^maxIntBlock)(intint) = ^(int a, int b){return a>b?a:b;};  
  2. - (void)fooBar  
  3. {  
  4.      int(^maxIntBlockCopied)(intint) =[maxIntBlock copy];  
  5. }  
  6. void foo()  
  7. {  
  8.      int(^maxIntBlockCopied)(intint) = Block_copy(maxIntBlock);  
需要注意的是,这里复制过后的block依旧位于全局区,实际上,复制操作是直接返回了原block对象。


三、block引用的变量在哪里

1.全局区

全局区的变量存储位置与block无关:

  1. static int gVar = 0;  
  2. //__block static int gMVar = 1;  
  3. void foo()  
  4. {  
  5.     static int stackVar = 0;  
  6. //    __block static int stackMVar = 0;  
                       注意: static变量是不允许添加__block标记的

           2.堆栈
  1. void foo()
    {
       
    __blockint i = 1024;//此时i在栈上
        int j = 1;//此时j在栈上
        void (^block)(void);
        block = ^(void){NSLog(@"%i %i",i,j);};//此时由于block在栈上,所以其所使用的变量也在栈上
        block();
        j++;
        void (^blockH)(void) =Block_copy(block);//复制block后,block位于堆上,有__block标记的i会复制一份到堆上,没有__block标记的j依旧位于栈上没有变动。
    }

    此时,你可能会问,当函数foo返回后,栈上的j已经回收,那么blockH怎么能继续使用它?这是因为没有__block标记的变量,会被当做实参传入block的底层实现函数中,当block中的代码被执行时,j已经不是原来的j了.

    另外,如果使用到变量j的所有block都没有被复制至堆,那么这个变量j也不会被复制至堆。

    四、其他特性

    1.复制的行为

    对block调用复制,有以下几种情况:

    1).对全局区的block调用copy,会返回原指针,并且这期间不处理任何东西(至少目前的内部实现是这样);

    2).对栈上的block调用copy,每次会返回新复制到堆上的block的指针,同时,所有__block变量都会被复制至堆一份(多次拷贝,只会生成一份)。

    3).对已经位于heap上的block,再次调用copy,只会增加block的引用计数。

    为什么我们不讨论retian的行为?原因是并没有Block_retain()这样的函数,而且objc里面的retain消息发送给block对象后,其内部实现是什么都不做。

    2.objc类中的block复制

    objc类实例方法中的block如果被复制至heap,那么当前实例会被增加引用计数,当这个block被释放时,此实例会被减少引用计数。

    但如果这个block没有使用当前实例的任何成员,那么当前实例不会被增加引用计数。这也是很自然的道理,我既然没有用到这个instance的任何东西,那么我干嘛要retian它?

    我们要注意的一点是,我看到网上有很多人说block引起了实例与block之间的循环引用(retain-cycle),并且给出解决方案:不直接使用self而先将self赋值给一个临时变量,然后再使用这个临时变量。

    但是,大家注意,我们一定要为这个临时变量增加__block标记。

clang -rewrite-objc block.c


http://mobile.51cto.com/hot-403914.htm

http://www.51cto.com/php/search.php?t=news&q=block&s=&ie=utf-8

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值