一、在使用block前須要對block指針作判空處理。html
不判空直接使用,一旦指針爲空直接產生崩潰。ios
一、在使用block前須要對block指針作判空處理。html
不判空直接使用,一旦指針爲空直接產生崩潰。ios
if (!self.isOnlyNet) { if (succBlock == NULL) { //後面使用block以前要先作判空處理 return; } id data = [NSKeyedUnarchiver unarchiveObjectWithFile:[self favoriteFile]]; if ([data isKindOfClass:[NSMutableArray class]]) { succBlock(data,YES); }else{ succBlock(nil,YES); } }
三、在block使用以後要對,block指針作賦空值處理,若是是MRC的編譯環境下,要先release掉block對象。web
block做爲類對象的成員變量,使用block的人有可能用類對象參與block中的運算而產生循環引用。多線程
將block賦值爲空,是解掉循環引用的重要方法。(不能只在dealloc裏面作賦空值操做,這樣已經產生的循環引用不會被破壞掉)google
typedef void(^SuccBlock)(id data); @interface NetworkClass { SuccessBlock _sucBlock; } @property (nonatomic,assign)BOOL propertyUseInCallBack; - (void) requestWithSucBlock: (SuccessBlock) callbackBlock; @end @implementation NetworkClass - (void) requestWithSucBlock: (SuccessBlock) callbackBlock { _sucBlock = callbackBlock;//MRC下:_sucBlock = [callbackBlock copy]; 不copy block會在棧上被回收。 } - (void) netwrokDataBack: (id) data { if (data != nil && _sucBlock != NULL) { _sucBlock(data); } //MRC下:要先將[_sucBlock release];(以前copy過) _sucBlock = nil; //Importent: 在使用以後將Block賦空值,解引用 !!! } @end //=======================如下是使用方=========================== @implementation UserCode - (void) temporaryNetworkCall { NetworkClass *netObj = [[NetworkClass alloc] init]; netObj.propertyUseInCallBack = NO; [netObj requestWithSucBlock: ^(id data) { //因爲block裏面引用netObj的指針因此這裏產生了循環引用,且因爲這個block是做爲參數傳入對象的,編譯器不會報錯。 //所以,NetworkClass使用完block以後必定要將做爲成員變量的block賦空值。 if (netObj.propertyUseInCallBack == YES) { //Do Something... } }]; } @end
還有一種改法,在block接口設計時,將可能須要的變量做爲形參傳到block中,從設計上解決循環引用的問題。atom
若是上面Network類設計成這個樣子:url
@class NetowrkClass; typedef void(^SuccBlock)(NetworkClass *aNetworkObj, id data); @interface NetworkClass //... @end @implementation NetworkClass @end @implementation UserCode - (void) temporaryNetworkCall { NetworkClass *netObj = [[NetworkClass alloc] init]; netObj.propertyUseInCallBack = NO; [netObj requestWithSucBlock: ^(NetworkClass *aNetworkObj, id data) { //這裏參數中已經有netObj的對象了,使用者不用再從block外引用指針了。 if (aNetworkObj.propertyUseInCallBack == YES) { //Do Something... } }]; } @end
四、使用方將self或成員變量加入block以前要先將self變爲__weakspa
五、在多線程環境下(block中的weakSelf有可能被析構的狀況下),須要先將self轉爲strong指針,避免在運行到某個關鍵步驟時self對象被析構。.net
第4、第五條合起來有個名詞叫weak–strong dance,來自於2011 WWDC Session #322 (Objective-C Advancements in Depth)線程
如下代碼來自AFNetworking,堪稱使用weak–strong dance的經典。
__weak __typeof(self)weakSelf = self; AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf; strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } };
第一行:__weak __typeof(self)weakSelf = self;
如以前第四條所說,爲防止callback內部對self強引用,weak一下。
其中用到了__typeof(self),這裏涉及幾個知識點:
a. __typeof、__typeof__、typeof的區別
恩~~他們沒有區別,可是這牽扯一段往事,在早期C語言中沒有typeof這個關鍵字,__typeof、__typeof__是在C語言的擴展關鍵字的時候出現的。
typeof是現代GNU C++的關鍵字,從Objective-C的根源說,他其實來自於C語言,因此AFNetworking使用了繼承自C的關鍵字。
b.對於老的LLVM編譯器上面這句話會編譯報錯,因此在很早的ARC使用者中流行__typeof(&*self)這種寫法,緣由以下
大體說法是老LLVM編譯器會將__typeof轉義爲 XXX類名 *const __strong的__strong和前面的__weak關鍵字對指針的修飾又衝突了,因此加上&*對指針的修飾。
第三行:__strong __typeof(weakSelf)strongSelf = weakSelf;
按照以前第五條的說法給轉回strong了,這裏__typeof()裏面寫的是weakSelf,裏面寫self也沒有問題,由於typeof是編譯時肯定變量類型,因此這裏寫self 不會被循環引用。
第4、5、六行,若是不轉成strongSelf而使用weakSelf,後面幾句話中,有可能在第四句執行以後self的對象可能被析構掉,而後後面的StausBlock沒有執行,致使邏輯錯誤。
最後第五行,使用前對block判空。
寫在最後,閱讀好的開源庫源碼是提升我的水平的一個很好途徑,看見不懂的地方去查去摸索會獲得更多。