Objective-C的Block实质与实现探究 part-4

Block中使用__block变量的情况


Block要修改值的第二种方法:使用__block说明符,全称为__block存储域类说明符。C语言中有以下存储域类说明符:

  • typedef
  • extern
  • static
  • auto
  • register

__block说明符类似于staticautoregister说明符,它们用于指定将变量值设置到哪个存储域中。例如,auto表示作为自动变量存储在栈中,static表示作为静态变量存储在数据区中。以下是分析例子:

Objective-C

__block int val = 10;
void (^blk)(void) = ^{ val = 1; };

C++

struct __Block_byref_val_0 { 
    void *__isa;
    __Block_byref_val_0 *__forwarding;
    int __flags;
    int __size;
    int val;
};

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0 *Desc;
    __Block_byref_val_0 *val;

    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    __Block_byref_val_0 *val = __cself->val;
    
    (val->__forwarding->val) = 1;
}

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);
}

static void __main_block_dispose_0(struct __main_block_impl_0 *src) {
    _Block_object_dispose(src->val, BLOCK_FIELD_IS_BYREF);
}

static struct __main_block_desc_0 {
    unsigned long reserved;
    unsigned long Block_size;
    void (*copy)(struct __main_block_impl_0 *, struct __main_block_impl_0 *);
    void (*dispose)(struct __main_block_impl_0 *);
}  __main_block_desc_0_DATA = {
    0,
    sizeof(struct __main_block_impl_0),
    __main_block_copy_0,
    __main_block_dispose_0
};

int main() {

    __Block_byref_val_0 val = {
        0,
        &val,
        0,
        sizeof(__Block_byref_val_0),
        10
    };

    blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x22000000);

    return 0;
}
Objective-C的Block实质与实现探究 part-4_第1张图片
Block数据结构图(6)

新增的部分以粉红色显示。

从图中看到,__block变量被转换为_Block_byref_val_0结构体,Block的成员变量有一个指向该结构体的指针。Block成员变量保留指针而不是一个结构体的设计,是为了能够在多个Block使用__block变量。下面是说明这个问题的例子。

__block int val = 10;
void (^blk0)(void) = ^{ val = 0;};
void (^blk1)(void) = ^{ val = 1;};
__Block_byref_val_0 val = {
    0, 
    &val, 
    0,
    sizeof(__Block_byref_val_0),
    10
};

blk0 = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x22000000);

blk1 = &__main_block_impl_1(__main_block_func_1, &__main_block_desc_1_DATA, &val, 0x22000000);

两个Block都使用了__Block_byref_val_0结构体实例val的指针。这样一来就可以从多个Block中使用同一个__block变量。当然,反过来从一个Block中使用多个__block变量也没有问题。只要增加Block的结构体成员变量与构造函数的参数,便可对应使用多个__block变量

Block数据结构图(6)中Desc新增的两个函数指针,copy函数用于�复制Block,dispose函数用于废弃Block。

Objective-C的Block实质与实现探究 part-4_第2张图片
《Objective-C高级编程 iOS与OS X多线程和内存管理》表2-6

上例的int型__block变量转换成结构体之后,有一个void *__isa指针的成员变量,这说明我们也可以把它看作实例。

Objective-C的Block实质与实现探究 part-4_第3张图片
《Objective-C高级编程 iOS与OS X多线程和内存管理》表2-2

你可能感兴趣的:(Objective-C的Block实质与实现探究 part-4)