一 概述
闭包就是1个函数或指向函数的指针+该函数的执行的上下文变量(也就是自由变量),Block是OC对于闭包的实现。其中Block可以定义在方法的内部或外部,其本质是对象,作用是使代码高聚合,只有调用Block的时候,才会调用代码块里的内容。
使用clang将OC代码转换为C++文件查看block的方法:
- 在命令行输入代码 clang -rewrite-objc 需要编译的OC的.m文件(如果这步报错找不到UIKit,就是用这个命令生成 clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk 需要编译的OC的.m)
- 这时查看当前的文件夹里 多了一个相同名称的 .cpp文件,可以在命令行输入 open 生成的.cpp 查看文件
开发中常用typedef定义一个block
void(^myBlock)(void);
使用时直接
@property (nonatomic, copy) myBlock blk;
self.blk = ^(){
NSLog(@"typedef定义的block");
};
定义一个无参数无返回值的block
void(^myBlock1)(void) = ^(){
NSLog(@"我是无参无返回值block");
};
定义一个有参数无返回值的block
void(^myBlock2)(NSString* string) = ^(NSString* string) {
NSLog(@"我是有参数无返回值block");
};
定义一个有参数有返回值的block
NSString*(^myBlock3)(NSString* string) = ^(NSString* string){
return [string stringByAppendingString:@"我是有参数有返回值的block"];
};
二 Block与外部变量
截取局部变量的值
- 默认情况下,对于block外的变量引用,block是将其值复制到block内部的结构体中来访问的,也就是说block的自动变量的截取只针对block块内部使用的自动变量,不使用则不截取。特别注意默认情况下block只能访问不能修改局部变量的值。
int a = 10;
void(^myBlock)(void) = ^{
NSLog(@"a的值是%d",a);
};
a = 20;
myBlock();
输出结果为a=10
,因为在a = 20赋值之前,a=10的值被截取到了block内部,a不管外部怎么变化,block内部的a永远都为10。
使用__block修饰的外部变量
对于用__block修饰的外部变量的引用,block是复制其引用地址来实现访问的,所以block内部可以修改__block修饰的外部变量的值。
__block int a = 10;
void(^myBlock)(void) = ^{
NSLog(@"a的值是%d",a);
};
a = 20;
myBlock();
输出结果为a=20
为什么__block修饰的外部变量的值就可以在block内部修改呢?
我们使用clang 将这个.m文件转成 .cpp查看一下
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
void(*myBlock)(void) = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
(a.__forwarding->a) = 20;
发现局部变量a变成了__Block_byref_a_0结构体类型的自动变量实例
网友评论