Block介紹
對象與對象之間的通信方式
代理-協(xié)議劫扒,通知檬洞,Block。
三種通信方式都實現(xiàn)了對象之間的解耦合沟饥。
通知的通信方式是1對多添怔。
代理湾戳、Block是1對1
Block介紹
Block是iOS4.0之后新增的一種語法結(jié)構(gòu),也稱為“閉包”广料。
Block是一個匿名的函數(shù)代碼塊砾脑,此代碼塊可以作為參數(shù)傳遞給其他對象。
可以把block當(dāng)做Objective-C的匿名函數(shù)性昭,block是OC中的一種數(shù)據(jù)類型拦止,
^
是block的特有標記Block格式說明
(返回類型)(^block名稱)(參數(shù)類型)=^(參數(shù)列表){代碼實現(xiàn)};
如果沒有參數(shù)县遣,等號后面參數(shù)列表的
()
可以省略糜颠。Block的3種類型
不管在
ARC
還是MRC
環(huán)境下,block內(nèi)部如果沒有訪問外部變量萧求,這個block是全局block__NSGlobalBlock__
其兴,形式類似函數(shù),存儲在內(nèi)存中的代碼區(qū)夸政。在
MRC
下元旬,block內(nèi)部如果訪問外部變量,這個block是棧block__NSStackBlock__
守问,存儲在內(nèi)存中的棧上匀归。在
MRC
下,block內(nèi)部訪問外部變量耗帕,同時對該block做一次copy操作穆端,這個block是堆block__NSMallocBlock__
,存儲在內(nèi)存中的堆上仿便。在
ARC
下体啰,block內(nèi)部如果訪問外部變量,這個block是堆block__NSMallocBlock__
嗽仪,存儲在內(nèi)存中的堆上荒勇,因為在ARC下,默認對block做了一次copy操作闻坚。
局部變量
局部自動變量沽翔,在Block中可被讀取。Block定義時copy變量的值窿凤,在Block中作為常量使用仅偎,所以即使變量的值在Block外改變,也不影響他在Block中的值卷玉,Block此時對局部變量只是做了值傳遞的操作哨颂。
static 修飾的全局變量
因為全局變量或靜態(tài)變量在內(nèi)存中的地址是固定的,Block在讀取該變量值的時候是直接從其所在內(nèi)存地址讀出相种,獲取到的是最新值威恼,而不是在定義時copy的常量
__block __weak __strong 這都是做什么的
__block 修飾的變量
某些場景下品姓,我們需要在Block內(nèi)部對外部變量進行修改。這時需要使用__block來修飾該變量實現(xiàn)在Block內(nèi)部的修改箫措,此時Block是復(fù)制其引用地址來實現(xiàn)訪問的腹备。
比較__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內(nèi)部對self默認都是強引用植酥。在ARC下,編譯器將Block從棧區(qū)拷貝到堆區(qū)弦牡,Block會強引用和持有self友驮,而self 也會強引用和持有Block,于是就造成了循環(huán)引用驾锰。
- 此時就需要使用__weak卸留,在修飾變量時,修飾符修飾變量self椭豫,讓 block 不強引用self耻瑟,從而破除循環(huán)。
__weak typeof(self) weakSelf = self;
self.passValueBlock = ^(NSString *string){
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.pointView.startLabel.text = string;
});
}
弱引用不會影響對象釋放赏酥,當(dāng)一個對象被釋放是喳整,所有指向它的弱引用會被置空,也避免出現(xiàn)野指針裸扶。
__strong
- 上面提到框都,__weak很好的解決retain Cycle,但還是會存在一些隱患姓言。不知道self什么時候被釋放瞬项,為了保證在Block內(nèi)部不會被釋放,所以使用__strong修飾何荚。
- Block內(nèi)部對對象采用strong修飾后囱淋,既使原持有對象在block外部已經(jīng)被釋放,但Block內(nèi)部扔能持有餐塘,于是執(zhí)行完Block后妥衣,該對象才被dealloc。
總結(jié):weakSelf是為了Block不持有self戒傻,避免循環(huán)引用税手,而再聲明一個strongSelf是因為一旦進入Block執(zhí)行,就不允許self在這個執(zhí)行過程中釋放需纳。Block執(zhí)行完后這個strongSelf會自動釋放芦倒,沒有循環(huán)引用問題不翩。
最后兵扬,使用Block時的注意事項
Block內(nèi)部不能直接修改局部變量
Block內(nèi)部可以訪問外部的變量, 默認是將其拷貝到其數(shù)據(jù)結(jié)構(gòu)中來實現(xiàn)訪問的, 屬性是只讀的. Block內(nèi)部不能修改外面的局部變量.
如果要修改需要對要修改的局部變量用__block修飾, 這樣局部變量就可以在Block內(nèi)部修改了麻裳,Block是復(fù)制其引用地址來實現(xiàn)訪問的
當(dāng)Block里面的出現(xiàn)self,造成的循環(huán)引用
循環(huán)引用就是當(dāng)self 擁有一個Block的時候,在Block中又調(diào)用self的方法器钟。形成了你中有我津坑,我中有你,造成誰都無法將誰釋放傲霸。從而發(fā)生內(nèi)存泄漏疆瑰。
解決方法:
__weak typeof (self) weakSelf = self;
- 定義一個weakSelf變量并加上__weak修飾符,在Block代碼塊中昙啄,所有需要self的地方都用weakSelf來替代穆役。這樣就不會增加引用計數(shù),所以Block持有self對象也就不會造成循環(huán)引用跟衅,從而避免內(nèi)存泄漏孵睬。