Q:什么是Block?
A:Block是将函数及其执行上下文封装起来的对象
block的三种存储状态:
NSGlobalBlock 在静态存储区,生存周期长,对其release或者copy retain没有用。是计算机管理的空间,程序退出就释放空间。
NSStackBlock 在栈上,对其进行retain 或者release无效,栈上空间是计算机自动释放的,copy后会拷贝到堆空间,下来就是nsmallocBlock。
NSMallocBlock 是堆上空间,对其retain,release,copy都有用,但是其引用计数器都是1,打印不会变。
Block 关键字使用
使用弱引用会带来另一个问题,weakSelf 有可能会为 nil,如果多次调用 weakSelf 的方法,有可能在 block 执行过程中 weakSelf 变为 nil。因此需要在 block 中将 weakSelf “强化“
__weak __typeof__(self) weakSelf = self;
NSBlockOperation *op = [[[NSBlockOperation alloc] init] autorelease];
[ op addExecutionBlock:^ {
__strong __typeof__(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doMoreThing];
} ];
[someOperationQueue addOperation:op];
__strong 这一句在执行的时候,如果 WeakSelf 还没有变成 nil,那么就会 retain self,让 self 在 block 执行期间不会变为 nil。这样上面的 doSomething 和 doMoreThing 要么全执行成功,要么全失败,不会出现一个成功一个失败,即执行到中间 self 变成 nil 的情况。
Block与外界变量
(1)默认情况
对于 block 外的变量引用,block 默认是将其复制到其数据结构中来实现访问的。也就是说block的自动变量截获只针对block内部使用的自动变量, 不使用则不截获, 因为截获的自动变量会存储于block的结构体内部, 会导致block体积变大。
block只能访问不能修改局部变量的值。
int age = 10;
myBlock block = ^{
NSLog(@"age = %d", age);
};
age = 18;
block(); //输出 10
(2) __block 修饰的外部变量
对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的
__block int age = 10;
myBlock block = ^{
NSLog(@"age = %d", age);
};
age = 18;
block(); //输出18
2、__block 修饰的外部变量的值就可以被block修改
我们使用 clang 将 OC 代码转换为 C++ 文件:
clang -rewrite-objc 源代码文件名
__block int val = 10;
转换成
__Block_byref_val_0 val = {
0,
&val,
0,
sizeof(__Block_byref_val_0),
10
};
会发现一个局部变量加上__block修饰符后竟然跟block一样变成了一个__Block_byref_val_0结构体类型的自动变量实例。
此时我们在block内部访问val变量则需要通过一个叫__forwarding的成员变量来间接访问val变量。
block的循环引用
参考链接
如下代码不需要使用__block,因为是对数组的操作而不是数组的赋值。浅谈Block 尾部有Block注意事项题目
NSMutableArray *arrM = [NSMutableArray array];
void (^testBlock)(void) = ^{
[arrM addObject:@"addObj"];
};
testBlock();
网友评论