iOS中的Block二

2019-01-27  本文已影响9人  你weixiao的时候很美
1.变量分类:

变量可以分为:
自动变量(局部变量)
静态变量,
全局变量,
全局静态变量
函数参数

2. Block的存储域
  1. block作为对象来看待的时候,有3种类型:

2._NSConcreteGlobalBlock
当block的代码块不使用应截获的自动变量的时候,或者记述全局变量的地方有block语法时,block是_NSConcreteGlobalBlock类型的block,存在于数据区(.data区)。

3._NSConcreteStackBlock
除NSConcreteGlobalBlack外,使用block语法生成的block都设置在栈上,是NSConcreteStackBlock类型的变量。

4._NSConcreteStackBlock
在栈上的block可以通过copy方法复制到堆上,这就是为何block可以超出自动变量的作用域继续存在。

ARC下,绝大多数情况下Block从栈上复制到堆上的代码由编译器实现:

ARC下,有一种情况编译器无法判断:向方法的参数中传递block的时候。

3.block可以截获自动变量的值。

1.首先:block结构体中增加了自动变量。

struct __main_block_impl_0 {
    // 成员变量
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;

   // Block体中使用的“自动变量”被复制到该结构体。
    id __strong obj;    //对象类型复制指针变量。
    int val;            //非对象类型直接复制变量。
}
  1. 初始化block结构体的时候,给block中的增加的自动变量赋值:
impl.isa = &_NSConcreteStackBlock; 
impl.Flags = 0;
impl.FuncPtr = __main_block_func_0;  
Desc = __mian_block_desc_0_DATA;

//给block结构体中的变量赋值
var = 10;
obj = 指针变量存的地址。

3.使用的时候如下:

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

 int val = __cself->val; 
 id obj  =  __cself->obj;
}
4. 使用__block

使用__block的时候,将自动变量复制到堆上,对该自动变量进行内存管理。block中有指针指向改自动变量,可以改变自动变量的值。

  1. 首先看下__block的实现:

__block int var = 10; 如下:
__block id obj = [[NSObject alloc] init];

// 结构体 __Block_byref_val_0
struct __Block_byref_val_0 {
    // 成员变量
    void *__isa;
    __Block_byref_val_0 *__forwarding;
    int __flags;
    int __size;
    int val;  // 相当于原自动变量的成员变量
};

// 结构体 __Block_byref_obj_0
struct __Block_byref_obj_0 {
    void *__isa;
    __Block_byref_obj_0 *__forwarding;
    int __flags;
    int __size;
    void (*__Block_byref_id_object_copy)(void*, void*);
    void (*__Block_byref_id_object_dispose_)(void*);
    __strong id obj; // __block变量被追加为成员变量
};

2.在block的结构体变化:
__block类型如下:

struct __main_block_impl_0 {
    // 成员变量
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;

    __Block_byref_val_0 *val;  //  指向__Block_byref_val_0结构体的指针 
   __Block_byref_obj_0 *obj; 
}
  1. 编译时增加2个函数copy函数 和disose函数:
// 静态函数 __main_block_copy_0
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src){
    _Block_object_assign(&dst->val, src->val, BLOCK_FIELD_IS_BYREF);
}

// 静态函数 __main_block_dispose_0
static void __main_block_dispose_0(struct __main_block_impl_0*src){
    _Block_object_dispose(src->val, BLOCK_FIELD_IS_BYREF);
}

4.调用的时候,对于__block类型变量:

// 静态函数 __main_block_func_0 (Block语法表达式发生的转换)
static void __main_block_func_0(struct __main_block_impl_0 *__cself)
{
    __Block_byref_val_0 *val = __cself->val;

    (val->__forwarding->val) = 1;
}
_forward成员变量的实现

__block变量的结构体成员变量__forwarding可以实现无论__block变量配置在栈上还是堆上时都能够正确地访问__block变量。

5.循环引用:

对象类型可以持有block,block也可以持有对象类型,就可能会造成循环引用。此时,使用__weak来修饰对象给block引用,可以打破循环。

6.总结:
上一篇 下一篇

猜你喜欢

热点阅读