OC 中的 block
OC 中的 block
[toc]
块对象(block)不是 OC 的特性而是 C 语言的实现,用一句话来概括 block:带有自动变量(局部变量)的匿名函数,在其他编程语言中,它与闭包(closure)的功能相同。
代码块的定义:
void (^myBlock)(void);
使用 typedef 关键字简化 block 的定义
//定义
typedef int (^myBlock)(int a, int b);
//使用
myBlock fun1 = ^(int a, int b){
return a * b;
};
代码块的几种使用形式
// 无参数无返回值
void (^BlockOne)(void) = ^(void){
NSLog(@"无参数,无返回值");
};
BlockOne();//block的调用
// 有参数无返回值
void (^BlockTwo)(int a) = ^(int a){
NSLog(@"有参数,无返回值, 参数 = %d,",a);
};
BlockTwo(100);
// 有参数有返回值
int (^BlockThree)(int,int) = ^(int a,int b){
NSLog(@"有参数,有返回值");
return a + b;
};
BlockThree(1, 5);
// 无参数有返回值
int(^BlockFour)(void) = ^{
NSLog(@"无参数,有返回值");
return 100;
};
BlockFour();
代码块的几种使用方式
- 可以像函数一样使用
int (^square_block)(int number) = ^(int number){ return (number * number);};
int result = square_block(5);
- 作为参数传递给函数
void q_sort(void *base, size_t nel, size_t width, int ^(compare)(const void *, const void *));
探究 block 的本质
看看下面的例子分别打印出什么:
#import <Foundation/Foundation.h>
void blockFunc1()
{
int num = 100;
void (^block)() = ^{
NSLog(@"num equal %d", num);
};
num = 200;
block();
}
void blockFunc2()
{
__block int num = 100;
void (^block)() = ^{
NSLog(@"num equal %d", num);
};
num = 200;
block();
}
int num = 100;
void blockFunc3()
{
void (^block)() = ^{
NSLog(@"num equal %d", num);
};
num = 200;
block();
}
void blockFunc4()
{
static int num = 100;
void (^block)() = ^{
NSLog(@"num equal %d", num);
};
num = 200;
block();
}
int main() {
blockFunc1();
blockFunc2();
blockFunc3();
blockFunc4();
return 0;
}
将自己的答案和打印出来的值对比一下,然后带着疑问继续下去
将 main.m 文件在命令行打开,然后执行以下语句
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
就会看到 main.m 文件所在目录有一个 C++ 的文件出现,打开,然后拖到最底下
可以看到 blockFunc1 的 C 语言实现
void blockFunc1()
{
int num = 100;
void (*block)() = ((void (*)())&__blockFunc1_block_impl_0((void *)__blockFunc1_block_func_0, &__blockFunc1_block_desc_0_DATA, num));
num = 200;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
去掉类型转换可以看到
void blockFunc1()
{
int num = 100;
void (*block)() = &__blockFunc1_block_impl_0(__blockFunc1_block_func_0, &__blockFunc1_block_desc_0_DATA, num));
num = 200;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
这里可以看到 block 其实就是一个指向结构体的指针
该结构体为:
struct __blockFunc1_block_impl_0 {
struct __block_impl impl;
struct __blockFunc1_block_desc_0* Desc;
int num;
__blockFunc1_block_impl_0(void *fp, struct __blockFunc1_block_desc_0 *desc, int _num, int flags=0) : num(_num) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
再看一下 blockFunc2 的 C 语言实现
void blockFunc2()
{
__attribute__((__blocks__(byref))) __Block_byref_num_0 num = {(void*)0,(__Block_byref_num_0 *)&num, 0, sizeof(__Block_byref_num_0), 100};
void (*block)() = ((void (*)())&__blockFunc2_block_impl_0((void *)__blockFunc2_block_func_0, &__blockFunc2_block_desc_0_DATA, (__Block_byref_num_0 *)&num, 570425344));
(num.__forwarding->num) = 200;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
发现 block 指向的结构体传入的是存储 num 的地址,所以 num 的值改变,传入函数的值也随之改变
------------- 本文结束 感谢阅读 -------------