OC高级编程 - Block 笔记

《Objective-C 高级编程》读书笔记

##前言
命令行编译objc文件

1
2
3
4
5
6
7
8
clang -fobjc-arc test.m -o test # 编译简单的oc文件,启用arc
clang -fobjc-arc -S test.m # 将test.m转成汇编 test.s
clang -fobjc-arc -framework Foundation test.m -o test # 编译 链接Foundation.framework
clang -rewrite-objc test.m # 将 oc源码转换成cpp源码

clang -fobjc-arc -arch arm64 test.m # 将test.m转成arm64汇编test.s
# 编译iPhone arm64版本
clang -fobjc-arc -framework Foundation test.m -o test -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.2.sdk

Block 本质

block可以类比函数指针,但是OC利用结构体的辅助来实现,该结构体开头为isa指针,所以可以用Object的方式管理。

以一个最简单的block.m文件为例

1
2
3
4
5
6
7
8
void test()
{
void (^blk)(void) = ^{
printf("hello block\n");
};

blk();
}

使用 clang -rewrite-objc block.m 将其转换为cpp,再查看block.cpp文件末尾内容

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
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

// block方法内容
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {

printf("hello block\n");
}

static struct __test_block_desc_0 {
size_t reserved;
size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};

// test()函数
void test()
{
void (*blk)(void) = ((void (*)()) &__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA));

((void (*)(__block_impl *)) ((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
}

// 可以在前面找到 __block_impl的定义
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

分析该文件:首先blk被声明为了函数指针,指向的是强制转换的 __test_block_impl_0 引用。
__test_block_impl_0 的第一个成员为 __block_impl ,而__block_impl 的第一个成员又是 isa,所以最终整个__test_block_impl_0 其实是一个OC对象,可以直接NSLog输出NSLog(@"blk = %@", blk); 处理,打印结果blk = <__NSGlobalBlock__: 0x100004150>