iOS Block 探索

Block:带有自动变量匿名函数

匿名函数:没有函数名的函数,一对{}包裹的内容是匿名函数的作用域。

自动变量:栈上声明的一个变量不是静态变量和全局变量,是不可以在这个栈内声明的匿名函数中使用的,但在Block中却可以。

准备Demo

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
#import "ViewController.h"

void (^block_global)(void) = ^ {
NSLog(@"block_global");
};

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

void (^block0)(void) = ^ {
NSLog(@"block0");
};

BOOL (^block1)(NSString *string) = ^(NSString *string) {
NSLog(@"%@", string);
return NO;
};

int a = 0;
NSString *b = @"hello";
NSArray *c = @[@"hello", @"world"];
NSMutableArray *d = c.mutableCopy;

__block double e = 1.0f;
__block NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"dictionary", @"key", nil];

BOOL (^block2)(NSNumber *number) = ^(NSNumber *number) {
NSLog(@"block%d\n%d %@ %@ %@ %f %@", number.intValue, a, b, c, d, e, dic);
return YES;
};

block0();
block1(@"block1");
block2(@2);
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

将ViewController.m编译成C++,以便研究,脚本命令如下:

1
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m

下面来逐一进行分析

block0

编译器生成的结构与实现

调用

block最终被还原成了一个结构体,成员:实现(imp)和描述(Desc)

block的调用事实上是调用结构体img的函数指针,并将结构体本身做为参数传入


imp

isa指向_NSConcreteStackBlock类

FuncPtr指向函数指针,参数是结构体指向自己的指针

Desc

存储结构体的大小

block1

与block0唯一的区别就在于多了一个传入的参数NSString

block2

相信读者也有发现,以上的常见block写法都imp的isa都是指向_NSConcreteStackBlock类。其实还会指向另一种类——_NSConcreteGlobalBlock,这种场景比较特殊,在全局里声明的block才会去指向这个类。

block_global

global block也有上面三种形态,在这里就不一一展示了。

-------------本文结束感谢您的阅读-------------