Block_byref - __block 修饰符
Contents
当捕获的对象拥有 __block
修饰符之后 Block 结构体中又增加一个成员,准确的说是本来被捕获的变量被继续包装了一层,用一个新的结构体来描述,这个结构体就是 Block_byref
struct Block_byref {
void *isa;
struct Block_byref *forwarding;
volatile int32_t flags; // contains ref count
uint32_t size;
};
struct Block_byref_2 {
// requires BLOCK_BYREF_HAS_COPY_DISPOSE
BlockByrefKeepFunction byref_keep;
BlockByrefDestroyFunction byref_destroy;
};
struct Block_byref_3 {
// requires BLOCK_BYREF_LAYOUT_EXTENDED
const char *lay
out;
};
这里有一个例子
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*);
NSObject *obj; // 这个就是被 __block 修饰的变量本身
};
copy 和 dispose 之上就是 byref 的基本版本,__block 修饰基本类型时就采用基本版本的 byref 来实现;如果涉及到对象,那么就需要管理对象的生命周期,引入 copy 和 dispose 方法。
descriptor 和 byref 拥有类似的设计,即分为基本实现和配备 copy/releaes 方法的处理对象的实现。在前文描述了使用指针操作取到 descriptor_2 的情况,byref 实现中也有类似的地方。但是写法却换了。
下面这段代码将栈上的 block 持有的 __block 对象复制到堆上去。
static struct Block_byref *_Block_byref_copy(const void *arg) {
struct Block_byref *src = (struct Block_byref *)arg;
if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
// src points to stack
struct Block_byref *copy = (struct Block_byref *)malloc(src->size);
copy->isa = NULL;
// byref value 4 is logical refcount of 2: one for caller, one for stack
copy->flags = src->flags | BLOCK_BYREF_NEEDS_FREE | 4;
copy->forwarding = copy; // patch heap copy to point to itself
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
if (src->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) {
// Trust copy helper to copy everything of interest
// If more than one field shows up in a byref block this is wrong XXX
// ----------- 在这里,使用以下语法获取 ------------------
struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src+1);
struct Block_byref_2 *copy2 = (struct Block_byref_2 *)(copy+1);
copy2->byref_keep = src2->byref_keep;
copy2->byref_destroy = src2->byref_destroy;
if (src->flags & BLOCK_BYREF_LAYOUT_EXTENDED) {
struct Block_byref_3 *src3 = (struct Block_byref_3 *)(src2+1);
struct Block_byref_3 *copy3 = (struct Block_byref_3*)(copy2+1);
copy3->layout = src3->layout;
}
(*src2->byref_keep)(copy, src);
}
else {
// Bitwise copy.
// This copy includes Block_byref_3, if any.
memmove(copy+1, src+1, src->size - sizeof(*src));
}
}
// already copied to heap
else if ((src->forwarding->flags & BLOCK_BYREF_NEEDS_FREE) == BLOCK_BYREF_NEEDS_FREE) {
latching_incr_int(&src->forwarding->flags);
}
return src->forwarding;
}
/// ????????
desc_2 = desc_1 + sizeof(struct Block_descriptor_1);
struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src+1);
/// 不知道 上面的换成这样能否成立
struct Block_descriptor_2 *desc2 = (struct Block_descriptor_1*)(desc + 1);
另外,这里看到 byref 引用计数加减就是以 2 为单位的,one for caller, one for stack。看不懂。。。。