1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
| // 由下面的代码可知: `__block`的作用就是定义一个新的结构体来包裹原来的变量
// 定义一个保存变量的结构体 (被__block标记的变量会被转化为这种格式的结构体对象)
struct __Block_byref_mutArr_0 {
void *__isa;
__Block_byref_mutArr_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
NSMutableArray *mutArr;
};
// block 结构体
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
// 包含捕获的局部变量的结构体指针
__Block_byref_mutArr_0 *mutArr; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_mutArr_0 *_mutArr, int flags=0) : mutArr(_mutArr->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
// 在block内部对`mutArr`操作 (block回调时执行的函数)
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
// 拿到 包含捕获的局部变量 的结构体指针
__Block_byref_mutArr_0 *mutArr = __cself->mutArr; // bound by ref
// 通过上面的结构体指针一步步拿到`mutArr`数组
((void (*)(id, SEL, ObjectType))(void *)objc_msgSend)((id)(mutArr->__forwarding->mutArr), sel_registerName("addObject:"), (id)((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 2));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst->mutArr, (void*)src->mutArr, 8/*BLOCK_FIELD_IS_BYREF*/);
}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->mutArr, 8/*BLOCK_FIELD_IS_BYREF*/);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t 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};
// main函数
int main(int argc, char *argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
// 这里可以看到结构体中的 __forwarding 指针其实指向的就是其自身
__attribute__((__blocks__(byref))) __Block_byref_mutArr_0 mutArr = {(void*)0,(__Block_byref_mutArr_0 *)&mutArr, 33554432, sizeof(__Block_byref_mutArr_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSMutableArray *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("array"))};
// 与不加__block差不多,`block`变量还是一个指向`__main_block_impl_0`结构体的指针,区别在于第三个参数变了. 第三个参数是包含局部变量`mutArr`的结构体指针.
// 即block捕获的是持有`mutArr`的结构体指针
void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_mutArr_0 *)&mutArr, 570425344));
// 在block外部对`mutArr`操作
//
// 此处对`mutArr`数组对象进行操作,获取`mutArr`也是和`block`内部的获取方法一样,
// 都是通过持有`mutArr`的结构体一步步获取到`mutArr`数组,
//
// 这里要经过 __forwarding 来获取`mutArr`的原因是:
// __block 标记的变量有可能被copy到堆上,__forwarding 的作用就是在变量被copy到堆上时修改指向,使栈和堆上的 __forwarding 都指向堆上的那个副本,这样就保证了block内外操作的都是同一份内存。
// 具体的copy实现可以参见下面的 `_Block_byref_copy` 函数。
//
// 举个例子:block外有个`__block int x = 2;`,当block被copy到堆上后这个warp变量也会生成一个新的对象地址,block内部使用的是新的对象,block外面用的还是原来栈上的那个,但我们期望的是不管内外,一方改变后另一方也要改变,所以需要指向同一份内存,这时候就是`__forwarding`的用武之地了。
//
// 所以,在block内外,操作的都是同一个`mutArr`对象.都是通过包含`mutArr`对象的`__Block_byref_mutArr_0`结构体对其进行间接操作处理的
// 这也就是为什么添加`__block`后还能改变原来的对象的原因
//
// PS: 在我们用__block 标记一个变量以后,当我们用到这个变量时都不是直接使用这个变量了,而是变成了通过`__Block_byref`来操作这个变量
((void (*)(id, SEL, ObjectType))(void *)objc_msgSend)((id)(mutArr.__forwarding->mutArr), sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_4t_ldgq93v932g220vwkl7c1fk40000gn_T_BlockTest_b07809_mi_0);
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
// __block 变量被copy到堆上时的具体实现
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;
// 堆上的forwarding指向其自身
copy->forwarding = copy; // patch heap copy to point to itself
// 栈上的forwarding指向copy到堆上的副本
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;
}
|