block(代码块)实际上就是oc语言对于闭包的实现。
在oc中,主要有三种类型的block:
1._NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。
2._NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
3._NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。
三种block的生成:
_NSConcreteGlobalBlock类型的block要么是空block,要么是不访问任何外部变量的block。它既不在栈中,也不在堆中。
_NSConcreteStackBlock类型的block有闭包行为,也就是有访问外部变量,并且该block只且只有有一次执行,因为栈中的空间是可重复使用的,所以当栈中的block执行一次之后就被清除出栈了,所以无法多次使用。
_NSConcreteMallocBlock类型的block有闭包行为,并且该block需要被多次执行。当需要多次执行时,就会把该block从栈中复制到堆中,供以多次执行。
在oc中使用时,大多都是保存在堆中的block。
关于 block 造成循环引用的问题:
循环引用:当两个对象都持有彼此而不能释放,导致内存泄漏即为循环引用。
概括起来说:只有block间接或直接被当前控制器持有,block内部使用时才应该用weakself,若当前控制器不持有block,在内部使用self并不会造成循环引用。
当在block内需要多次调用weak self时,有可能因为weak self被置为nil而导致crash,比如:在block中需要再开启一个线程调用self方法,若此时使用weak self有可能weak self已经被销毁了,而不能调用。这种情况需要配合使用strongself来避免。
block修改外部变量的值:
默认情况下,block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。
想要修改外部变量的值,就必须使用__block来修饰。而__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。