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內部也可以修改外部變量的值。