Block学习

#iOS Block 概要
##1.Block 的种类
block 常见的类型有三种: __NSGlobalBlock__(全局), __NSStackBlock__(栈), __NSMallocBlock(堆)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(int argc, const char *argv[]){
@autorelease{
int i = 10;
//ARC 情况下
^{i;};
//创建 block 的时候都是在 `栈` 中 --> StackBlock
void (^block) = ^{i;};
//block为 strong 类型,并且捕获了外部变量,所以赋值的时候,自动进行了 copy -> MallocBlock
__weak void (^weakBlock) = ^{i;};
//如果是 weak 类型的 block,不会自动进行 copy -> StackBlock
void (^stackBlock) = ^{};
//如果 block 是 strong 类型,并且没有捕获外部变量、或者用到全局变量,静态变量,那么就会被转换成 GlobalStack.
}
}

综上所述:我们可以得到如下的结论:ARC 下
1.block 没有捕获外部变量,或者用到全局变量、静态变量,则为 __NSGlobalBlock__
2.block 用到自动变量且用正常变量来接受这个 block,则是 MallocBlock
3.block 用到自动变量或者用 weak 变量来接受 block,则是 StackBlock

备注:
1.block 用到自动变量初创之时都是 StackBlock 类型,在 ARC 环境下赋值给正常变量时,系统会将 block 拷贝到堆上,StackBlock 变成了 MallocBlock
2.在 MRC 下,赋值给正常变量时,系统不会自动的将 block 拷贝到堆上。

###2.Block 内外关系

1
2
3
4
5
6
static int a;//全局或者局部变量都一样
- (void)test{
^{
a;
}
} //不向 block 内传递任何东西,(全局或者局部变量作用域广,任何时候用到变量 a 都是同一个变量,block 用到的变量 a 也是同一个)
1
2
3
4
5
6
- (void)test{
static int a;
^{
a = 10;
}
} //向 block 内传递地址(局部静态变量作用域有限,block 记录了局部静态变量的地址,确保了 block 内外用到的变量 a 是同一个)
1
2
3
4
5
6
- (void)test{
int a;
^{
a;
}
} // 向 block 内传递
1
2
3
4
5
6
- (void)test{
__block int a;
^{
a = 10;
}
} //向 block 内传递构造的结构体 __Block_byref

综上所述:__block 修饰的基础类型和对象类型都会构造__Block_byref结构体再传递。
构造__Block_byref结构体在传递的方式会很复杂。

###3.梳理
在 ARC 环境下,
__NSGlobalBlock__ 几乎不出现,使用起来没什么需要注意。
__NSStackBlock__ 几乎不出现, 但他是 __NSMallocBlock__ 的前身。
__NSMallocBlock__ 比较重要

看得懂编译是一切的前提

##1.看懂编译
编译选项:clang --rewrite-objc

A.不带参数

1
2
3
4
5
6
int main(int argc, const char *argv[]){
@autorelease{
^{}
}
return 0;
}

编译结果:

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
struct __block_impl{
void *isa;
int Flags;
int Reverse;
void *FuncPtr;
};

struct __main_block_impl_0{
struct __block_impl impl;
struct __main_block_desc_0 *Desc;
__main_block_desc_0(void *fp, struct __main_block_desc_0 *desc, int flags = 0){
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

static void __main_block_func_0(struct _main_block_impl_0 *__cself){}

static struct _main_block_func_0{
size_t reserved;
size_t Block_size;
}__main_block_desc_0_DATA = {0, sizeof(struct __main_block_impl_0);}

int main(int argc, const char* argv[]){
void(*test)()=(
(void (*))&__main_block_impl_0(
(void *)__main_block_func_9,
&__main_block_desc_0_DATA)
);
);

((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr((__block_impl *)test);
return 0;
}

__main_block_impl_0 就是 block 的一个 C++的实现,0 表示第几个block,其实就是一个结构体。
__block_impl 结构体中

  1. isa指向所属类,就是 block 的类型。
  2. flags,标志变量,在 block 内部操作中会用到。
  3. Reserved,是保留变量。
  4. FuncPtr,block 执行时调用的函数指针,它包含了 isa 指针,其实 block 也是一个对象。

__main_block_desc_0 结构体中

  1. Reserved,为保留字段
  2. Block_size 为 block 的大小,也就是sizeof(struct __main_block_impl_0)

在上面的代码中,定义__main_block_desc_0结构体时,同时创建了__main_block_desc_0_DATA,并给它赋值,以供main函数中对__main_block_0进行初始化。

  • __main_block_impl_0isa指向了__NSConcreteStackBlock
  • main函数中看,__main_block_impl_0FuncPtr指向了函数__main_block_func_0
  • __main_block_impl_0Desc也指向了定义的__main_block_desc_0时就创建的__main_block_desc_0_DATA,其中记录了 block 结构体大小等信息。

##2.Block 实际结构
Block_private.h 中定义了对 block 的相关结构体的真实定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Block_descriptor{
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *)
}

struct Block_layout{
void *isa;
int flags;
int reserved;
void (* invoke)(void *,...);
struct Block_descriptor *descriptor;
}
  1. invoke ,相当于上文中的 FuncPtr, block 执行时调用的函数指针,block 定义时内部的执行代码都在这个函数中。
  2. Block_descriptor,block 的详细描述
  3. copy/dispose,辅助拷贝/销毁函数,处理 block 范围外的变量时使用。

结论:
block 就是一个里面存储了指向函数体中包含定义 block 时代码块的函数指针,以及block 外部上下文等信息的结构体。

B. 基础类型

1
2
3
4
5
6
7
8
int main(int argc, const char *argv[]){
int any = 1;
void (^test)() = ^{
NSLog(@"%d", any);
};
test();
return 0;
}

编译结果:

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
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int any;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _any, int flags=0) : any(_any) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself){
int any = __cself->any; // bound by copy

NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_a_f8f541_mi_0, any);
}

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main (int argc, const char *argv[]){
int any = 1;
void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, any));
((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test);
return 0;
}

###C. 对象类型

1
2
3
4
5
6
7
8
int main(int argc, const char *argv[]){
NSString *any = [NSString stringWithFormat:@"1"];
void (^test)() = ^{
NSLog(@"%@", any);
};
test();
return 0;
}

编译结果:

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
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};


struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
NSString *any;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_any, int flags=0) : any(_any) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSString *any = __cself->any; // bound by copy

NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_b_ca6e15_mi_2, any);
}

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->any, (void*)src->any, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->any, 3/*BLOCK_FIELD_IS_OBJECT*/);}

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

int main (int argc, const char *argv[]){
NSString *any = ((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_b_ca6e15_mi_0, (NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_b_ca6e15_mi_1);
void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, any, 570425344));
((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test);
return 0;
}

###D.__block 修饰基础类型

1
2
3
4
5
6
7
8
int main(int argc, const char * argv[]) {
__block int any = 1;
void (^test)() = ^ {
NSLog(@"%d",any);
};
test();
return 0;
}

编译结果:

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
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

struct __Block_byref_any_0 {
void *__isa;
__Block_byref_any_0 *__forwarding;
int __flags;
int __size;
int any;
};

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_any_0 *any; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_any_0 *_any, int flags=0) : any(_any->__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_any_0 *any = __cself->any; // bound by ref

NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_c_88a22a_mi_0, (any->__forwarding->any));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->any, (void*)src->any, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->any, 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};
int main(int argc, const char *argv[]){
__attribute__((__blocks__(byref))) __Block_byref_any_0 any = {(void*)0,(__Block_byref_any_0 *)&any, 0, sizeof(__Block_byref_any_0), 1};
void(*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_any_0 *)&any, 570425344));
((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test);
return 0;
}

###E. __block修饰对象类型

1
2
3
4
5
6
7
8
int main(int argc, const char * argv[]) {
__block NSString * any = [NSString stringWithFormat:@"1"];
void (^test)() = ^ {
NSLog(@"%@",any);
};
test();
return 0;
}

编译结果:

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
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

struct __Block_byref_any_0 {
void *__isa;
__Block_byref_any_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
NSString *any;
};

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_any_0 *any; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_any_0 *_any, int flags=0) : any(_any->__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_any_0 *any = __cself->any; // bound by ref

NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_d_a788e6_mi_1, (any->__forwarding->any));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->any, (void*)src->any, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->any, 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};
int main(int argc, const char *argv[]){
__attribute__((__blocks__(byref))) __Block_byref_any_0 any = {(void*)0,(__Block_byref_any_0 *)&any, 33554432, sizeof(__Block_byref_any_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_d_a788e6_mi_0)};
void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_any_0 *)&any, 570425344));
((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test);
return 0;
}

##3. 结果分析
###3.1

  1. __main_block_func_0 为 block 具体实现函数
  2. __main_block_desc_0 为 block 大小描述 + 拷贝函数 + 销毁函数
  3. __main_block_impl_0 block 的一切都封装在内,包括前两个函数 + 捕获的参数。该结构体就是 block 在内存里的真实存在。
  4. block 的调用((void (*)(__block_impl *)) ((__block_impl *)test) -> FuncPtr)((__block_impl *)test);

###3.2 以 A 为例 block 的调用

1
2
void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0,&__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test);
  1. 调用__main_block_impl_0结构体的构造函数,生成__main_block_impl_0结构体的实例,获取实例地址,将这个地址转成函数地址。
  2. (void (*)(__block_impl *))读取地址,强转成函数
  3. ((__block_impl *)test)之类对象转换成父类,这个地方 test 指针真正的指向对象__main_block_impl_0,是一个子类对象,但是__main_block_impl_0包含了__block_impl结构体,所以读取子类对象的父类对象大小,就能取到了父类对象

###3.3 对象类型编译结果

  1. 拷贝__main_block_impl_0 -> __Block_byref_any
1
2
3
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst->any, (void*)src->any, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
  1. 销毁 __main_block_impl_0 -> __Block_byref_any
1
2
3
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->any, 3/*BLOCK_FIELD_IS_OBJECT*/);
}

###3.4 __block修饰编译结果有的

作者

shouyi.www

发布于

2019-12-04

更新于

2025-01-30

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×