Block介绍
-
对象与对象之间的通信方式
-
代理-协议,通知,Block。
-
三种通信方式都实现了对象之间的解耦合。
-
通知的通信方式是1对多。
-
代理、Block是1对1
-
Block介绍
-
Block是iOS4.0之后新增的一种语法结构,也称为“闭包”。
-
Block是一个匿名的函数代码块,此代码块可以作为参数传递给其他对象。
-
可以把block当做Objective-C的匿名函数,block是OC中的一种数据类型,
^
是block的特有标记 -
Block格式说明
-
(返回类型)(^block名称)(参数类型)=^(参数列表){代码实现};
-
如果没有参数,等号后面参数列表的
()
可以省略。 -
Block的3种类型
-
不管在
ARC
还是MRC
环境下,block内部如果没有访问外部变量,这个block是全局block__NSGlobalBlock__
,形式类似函数,存储在内存中的代码区。 -
在
MRC
下,block内部如果访问外部变量,这个block是栈block__NSStackBlock__
,存储在内存中的栈上。 -
在
MRC
下,block内部访问外部变量,同时对该block做一次copy操作,这个block是堆block__NSMallocBlock__
,存储在内存中的堆上。 -
在
ARC
下,block内部如果访问外部变量,这个block是堆block__NSMallocBlock__
,存储在内存中的堆上,因为在ARC下,默认对block做了一次copy操作。
局部变量
局部自动变量,在Block中可被读取。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值,Block此时对局部变量只是做了值传递的操作。
static 修饰的全局变量
因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存地址读出,获取到的是最新值,而不是在定义时copy的常量
__block __weak __strong 这都是做什么的
__block 修饰的变量
某些场景下,我们需要在Block内部对外部变量进行修改。这时需要使用__block来修饰该变量实现在Block内部的修改,此时Block是复制其引用地址来实现访问的。
比较__weak 和 __strong
这边用AFN中的一段代码
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
__weak
- 我们在使用Block时,有时候会用到self,而Block内部对self默认都是强引用。在ARC下,编译器将Block从栈区拷贝到堆区,Block会强引用和持有self,而self 也会强引用和持有Block,于是就造成了循环引用。
- 此时就需要使用__weak,在修饰变量时,修饰符修饰变量self,让 block 不强引用self,从而破除循环。
__weak typeof(self) weakSelf = self;
self.passValueBlock = ^(NSString *string){
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.pointView.startLabel.text = string;
});
}
弱引用不会影响对象释放,当一个对象被释放是,所有指向它的弱引用会被置空,也避免出现野指针。
__strong
- 上面提到,__weak很好的解决retain Cycle,但还是会存在一些隐患。不知道self什么时候被释放,为了保证在Block内部不会被释放,所以使用__strong修饰。
- Block内部对对象采用strong修饰后,既使原持有对象在block外部已经被释放,但Block内部扔能持有,于是执行完Block后,该对象才被dealloc。
总结:weakSelf是为了Block不持有self,避免循环引用,而再声明一个strongSelf是因为一旦进入Block执行,就不允许self在这个执行过程中释放。Block执行完后这个strongSelf会自动释放,没有循环引用问题。
最后,使用Block时的注意事项
-
Block内部不能直接修改局部变量
-
Block内部可以访问外部的变量, 默认是将其拷贝到其数据结构中来实现访问的, 属性是只读的. Block内部不能修改外面的局部变量.
-
如果要修改需要对要修改的局部变量用__block修饰, 这样局部变量就可以在Block内部修改了,Block是复制其引用地址来实现访问的
-
当Block里面的出现self,造成的循环引用
-
循环引用就是当self 拥有一个Block的时候,在Block中又调用self的方法。形成了你中有我,我中有你,造成谁都无法将谁释放。从而发生内存泄漏。
解决方法:
__weak typeof (self) weakSelf = self;
- 定义一个weakSelf变量并加上__weak修饰符,在Block代码块中,所有需要self的地方都用weakSelf来替代。这样就不会增加引用计数,所以Block持有self对象也就不会造成循环引用,从而避免内存泄漏。
网友评论