您的位置:首页 > 其它

简单了解Block

2017-01-15 14:46 381 查看
block一般作为回调函数,形式:

int (^blk_t)(int)=^int (int count){return count+1;},对应的是^ 返回类型(参数列表){表达式};

用typedef如下:

typedef int (^blk)(int );

blk elk_t=^(int count){return count+1};

一、截获变量

block能截获变量,但不能修改变量,想修改变量,变量前面加__block,即使是静态变量,静态全局变量也不能修改。

block截获了指针可以使用它,不能截获C数组。

block可截获:变量(int a,double b),对象(实际是指针)

(block将截获的变量作为自己的成员变量进行访问,超出作用域释放)

二、Block实质

白皮书上说block是OC类对象,我觉得它更像结构体实例对象。结构体实例变量和普通变量一样,在栈上分配空间,超出作用域会被释放。

类:类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存

结构:结构是值类型在栈上分配。
Block结构体:
struct
__main_block_impl_0

{

   
struct
__block_impl impl;

   
struct
__main_block_desc_0 *Desc;
   
//截获的自动变量,作为block的成员变量
   
id array;//截获对象

   
//结构体的函数
    __main_block_impl_0(void
*fp,struct
__main_block_desc_0 *desc,int
flags=0)

    {

        impl.isa=&NSConcreteStackBlock;

        impl.Flags=flags;

        impl.FuncPtr=fp;

        Desc=desc;

    }
};
定义完block之后,其实是创建了一个函数,在创建结构体的时候把函数的指针一起传给了block,所以之后可以拿出来调用。
有__block修饰的变量,实际上也是结构体实例。
struct
__Block_byref_val_0

{

    __isa;

    __forwarding;//指向自己的指针

    __flags;

    __size;

    val;        
//使用值
}
Block的struct
__main_block_impl_0结构体实例持有指向__block变量的struct
__Block_byref_val_0结构体实例指针。
三、Block的存储
Block实例和__block实例一般默认创建出来都是存储在栈上的,就像普通变量,
当作用域结束时,Block和__block会被复制到堆上,栈上__block变量的forwarding指针指向堆上的变量,这样就保证了变量同步。
需要复制的情况:
手动调用copy方法时;
Block作为函数的返回值;
将Block赋值给strong类型变量时;
在方法名中有usingBlock的Cocoa框架方法或GCD的API中传递Block时;
以上情况都会调用_Block_copy函数,除了以上情况下,推荐手动调用copy

复制实际调用的是_Block_copy方法,需要废弃时调用dispose方法。
Block截获两种变量,一种是_block修饰的变量,一种是对象(指针)

当Block调用copy函数时,Block持有截获对象的强引用,Block复制后强引用一直存在,所以被截获的对象不会被释放。

四、循环引用
最常见的是,类的成员变量有Block,Block函数里面引用self
破坏循环引用的方法:用__block变量tmp=self,Block里面用tmp,用完以后tmp置nil
                                    用__weak变量tmp=self,Block里面用tmp
在ARC无效时,__block变量用完以后不用赋值nil,因为ARC无效,Block复制到堆上时,不会对__block变量retain。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: