Block是OC,C或者是C++的一个特性,在其他语言中与之类似的功能称为闭包或者lambdas。在OC中,Block跟NSArray等对象一样,是属于OC的对象。
语法
声明一个block比较简单,通过^即可, block的执行的话,在{}后面加上()
-
无参无返回值:
void(^BlockOne)() = ^{ NSLog(@"This is a block"); }; // 执行 BlockOne()
* 有参数无返回值:
```ObjC
void(^BlockTwo)(double) = ^(double price) {
NSLog(@"The price is $%f", price);
};
BlockTwo(2.2);
-
有参数有返回值:
void(^BlockThree)(NSString) = ^(NSString *name) { return [NSString stringWithFormat:@"Hello, %@", name]; }; BlockThree(@"Lily"); -
无参数有返回值:
void(^BlockFour)() = ^{ return 77; } BlockFour();
Block的类型就上面四种,但是在实际开发中,我们常用typedef来定义block:
typedef void(^Block)(int) MyBlock;
@property (nonatomic, copy) MyBlock myBlock;
...
self.myBlock = ^(int age) {
// ...
};
外部变量
换种方式来说的话,Block可以说是一个特殊的函数,有自己的作用域,能接收参数,返回值等。除此之外,Block还能捕获外部的变量,比方说下面这段代码:
int a = 1;
NSLog(@"1 ----- address: %p -----%d", &a, a);
void(^myBlock)() = ^() {
NSLog(@"2 ----- address: %p -----%d", &a, a);
};
a = 2;
myBlock();
NSLog(@"3 ----- address: %p -----%d", &a, a);
// 输出:
// 2017-04-14 11:54:19.953 ObjectiveCDemo[53955:2103595] 1 ----- address: 0x7fff5889a55c -----1
// 2017-04-14 11:54:19.963 ObjectiveCDemo[53955:2103595] 2 ----- address: 0x60000005bdd0 -----1
// 2017-04-14 11:54:19.964 ObjectiveCDemo[53955:2103595] 3 ----- address: 0x7fff5889a55c -----2
可以看到,虽然我们在block外更改了a的值,但是对block内部已经捕获到的变量却没有影响。或许我们会多问一句为什么。事实上,在block捕获到外部变量的时候,会将外部变量的值copy一份到自己内部,并且在内部的这个变量是使用const修饰的,也就意味着在block内部我们不能修改这个变量.
如果我们想修改这个变量的话呢?可以用__block修饰这个外部变量:
__block int a = 1;
NSLog(@"1 ----- address: %p -----%d", &a, a);
void(^myBlock)() = ^() {
a = 3;
NSLog(@"2 ----- address: %p -----%d", &a, a);
};
a = 2;
myBlock();
NSLog(@"3 ----- address: %p -----%d", &a, a);
// 输出:
// 2017-04-14 12:03:54.163 ObjectiveCDemo[54150:2109805] 1 ----- address: 0x7fff5a5a9558 -----1
// 2017-04-14 12:03:54.170 ObjectiveCDemo[54150:2109805] 3 ----- address: 0x608000032418 -----2
// 2017-04-14 12:03:54.172 ObjectiveCDemo[54150:2109805] 2 ----- address: 0x608000032418 -----2
// 2017-04-14 12:03:54.173 ObjectiveCDemo[54150:2109805] 4 ----- address: 0x608000032418 -----2
从输出可以看到,使用__block进行修饰后,block捕获到的是其引用地址,因此就可以对block内部的值进行修改,并能在block的作用域外获取到更新的值。
关于block的更详细的讨论,可以看这里:iOS Block 详解
下面是自己的笔记:
-
block的类型
_NSConcreteGlobalBlock全局块。不访问外部变量_NSConcreteStackBlock栈块。MRC下访问外部变量的block_NSConcreteMallocBlock堆块。ARC下访问外部变量的block
-
ARC下的block 栈块的话,实际上还是在堆区的,只不过在ARC环境下,编译器将其复制到栈区来延长实例变量的周期,避免在堆区中实例变量在作用域结束的时候就被释放了。