Block基礎(chǔ)看它就夠了

Block基本用法

"Block語法"

1.作為方法時

- (void)testGlobalBlock:(NSString*) url

? ? ? ? ? ? ? ? ?success:(void(^)(BOOLisSuccess))success

? ? ? ? ? ? ? ? ? failure:(void(^)(BOOLisSuccess))failure;

2.作為成員變量進行聲明時

typedefvoid(^SUCCESSBLOCK)(BOOLisSuccess);

typedefvoid(^FAILEDBLOCK)(BOOLisSuccess);

@interfaceXXEngine()

@property(nonatomic,copy) SUCCESSBLOCK successBlock;

@property(nonatomic,copy) FAILEDBLOCK failedBlock;

@end

3.寫在函數(shù)內(nèi)部

void(^_block)() = ^{

_a =10;

};

內(nèi)存五個區(qū)認識

這里先普及一個基本的5個概念扶镀,內(nèi)存的5個區(qū)。否則在具體講堆棧的時候怕大家會不理解。

作用名稱

棧區(qū)(stack)由編譯器自動分配釋放运挫,存放函數(shù)的參數(shù)值烛恤,局部變量的值等

堆區(qū)(heap)一般由程序員分配釋放崎逃, 若程序員不釋放失尖,程序結(jié)束時可能由OS回收

全局區(qū)(靜態(tài)區(qū))(static)全局變量和靜態(tài)變量的存儲是放在一塊的妹窖,初始化的全局變量和靜態(tài)變量在一塊區(qū)域纬朝,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。程序結(jié)束后由系統(tǒng)釋放

文字常量區(qū)常量字符串就是放在這里的骄呼。程序結(jié)束后由系統(tǒng)釋放

程序代碼區(qū)存放函數(shù)體的二進制代碼

使用場景

任務完成時回調(diào)處理

消息監(jiān)聽回調(diào)處理

錯誤回調(diào)處理

枚舉回調(diào)

視圖動畫共苛、變換

排序

Block原理

Block三種類型

作用名稱

NSConcreteGlobalBlock全局靜態(tài)判没,不訪問外部變量的時候就是NSConcreteGlobalBlock

NSConcreteStackBlock保存在棧中,出花括號會被銷毀

NSConcreteMallocBlock保存在堆中的block,當引用計數(shù)為0的時候會被銷毀


ARC下判斷原則

"Block語法"

造成循環(huán)引用的實例

@implementationPerson

{

int_a;

void(^_block)();

}

- (void)test

{

void(^_block)() = ^{

_a =10;

};}

@end

此時_a在用clang編譯后可以很明顯看到有會self的身影俄讹,所以此時我們可以將其理解成self.a(便于記憶),此時Person持有block,block持有self哆致,造成了循環(huán)引用

解決方式

- (void)test

{

__weaktypeof(self) weakSelf =self;

void(^_block)() = ^{

weakSelf->a =10;

};}


經(jīng)驗談之GCD/UIView的系統(tǒng)動畫的Block中绕德,為何可以寫self患膛?

因為self并沒有對其進行持有,循環(huán)引用的原理是兩個對象之間相互有持有關(guān)系耻蛇,現(xiàn)在僅僅是GCD持有self踪蹬,但是self并沒有持有GCD,所以是沒有問題的臣咖。(當GCD對象為其成員變量時才具有持有的關(guān)系)


結(jié)論

我們觀察Block_byref_a_0結(jié)構(gòu)體跃捣,這個結(jié)構(gòu)體中含有isa指針,所以也是一個對象夺蛇,它是用來包裝局部變量a的疚漆。當block被copy到堆中時,Persontest_block_impl_0的拷貝輔助函數(shù)Persontest_block_copy_0會將Block_byref_a_0拷貝至堆中刁赦,所以即使局部變量所在堆被銷毀娶聘,block依然能對堆中的局部變量進行操作。其中Block_byref_a_0成員指針forwarding用來指向它在堆中的拷貝

利用對象做Block

"Block語法"

現(xiàn)在有RequestObject和XXNetEngine兩個文件.

1.RequestObject

#import

typedefvoid(^ReqSuccessBlock)(BOOLisSuccess);

typedefvoid(^FailedBlock)(BOOLisSuccess);

@interfaceRequestObject:NSObject

@property(nonatomic,copy) ReqSuccessBlock successBlock;

@property(nonatomic,copy) FailedBlock failedBlock;

@property(nonatomic,assign)NSIntegerCMD;

@property(nonatomic,assign)NSIntegerseq;

@end

2.XXNetEngine

#import"XXNetEngine.h"

#import"RequestObject.h"

@interfaceXXNetEngine()

@property(nonatomic,strong)NSMutableDictionary*requestDict;

@end

@implementationXXNetEngine

-(instancetype)init

{

if(self= [superinit]){

self.requestDict = [NSMutableDictionarydictionary];

}

returnself;

}

+(instancetype) sharedInstance

{

staticXXNetEngine* instance =nil;

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

instance = [[XXNetEngine alloc] init];

});

returninstance;

}

-(void)requestData:(RequestObject*) reqObject

successBlock:(void(^)(BOOLisSuccess))successBlock

failureBlock:(void(^)(BOOLisSuccess))failureBlock

{

if( reqObject && successBlock && failureBlock ) {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{

//requestSeq是一個隨機數(shù)

intrequestSeq = arc4random() %100;;

//網(wǎng)絡操作

reqObject.successBlock = successBlock;

reqObject.failedBlock = failureBlock;

reqObject.seq = requestSeq;

[selfaddRequestItem:reqObject seq:requestSeq];

//模擬一個2秒的網(wǎng)絡操作

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[selfdidReceiveData:reqObject.seq];

});});}}

- (void) didReceiveData:(NSInteger) seq

{

RequestObject *request = [selfgetRequestItem:seq];

if( request ) {

[selfremoveRequestItem:seq];

dispatch_async(dispatch_get_main_queue(), ^{

if(NULL!= request.successBlock ) {

request.successBlock(YES);

}});}}

//用命令字做參數(shù)傳遞

- (RequestObject *) getRequestItem:(NSInteger)seq

{

RequestObject *request =nil;

@synchronized(self) {

NSNumber*numSeq = [NSNumbernumberWithInteger:seq];

request = [self.requestDict objectForKey:numSeq];

}

returnrequest;

}

- (void) addRequestItem:(RequestObject *)request seq:(NSInteger)seq

{

@synchronized(self) {

if( request && (0!=seq) ) {

NSNumber*numSeq = [NSNumbernumberWithInteger:seq];

[self.requestDict setObject:request forKey:numSeq];

}}}

- (void) removeRequestItem:(NSInteger)seq

{

@synchronized(self) {

NSNumber*numSeq = [NSNumbernumberWithInteger:seq];

[self.requestDict removeObjectForKey:numSeq];

}}

@end

Delegate甚脉、Notification丸升、Block的比較

名稱優(yōu)點缺點

Notification1.使用簡單,代碼精簡牺氨。2.解決了同時向多個對象監(jiān)聽相應的問題狡耻。3.傳值方便快捷,Context自身攜帶相應的內(nèi)容猴凹。1.使用完畢后夷狰,要時刻記得注銷通知,否則將出現(xiàn)不可預見的crash郊霎。2.key不夠安全沼头,編譯器不會監(jiān)測是否被通知中心正確處理。3.調(diào)試的時候動作的跟蹤將很難進行歹篓。4.當使用者向通知中心發(fā)送通知的時候瘫证,并不能獲得任何反饋信息。5.需要一個第三方的對象來做監(jiān)聽者與被監(jiān)聽者的中介庄撮。

Delegate1.減少代碼的耦合性背捌,使事件監(jiān)聽和事件處理相分離。2.清晰的語法定義洞斯,減少維護成本毡庆,較強的代碼可讀性坑赡。3.不需要創(chuàng)建第三方來監(jiān)聽事件和傳輸數(shù)據(jù)。1.實現(xiàn)委托的代碼過程比較繁瑣么抗。2.當實現(xiàn)跨層傳值監(jiān)聽的時候?qū)⒓哟蟠a的耦合性毅否,并且程序的層次結(jié)構(gòu)將變的混亂。3.當對多個對象同時傳值響應的時候蝇刀,委托的易用性將大大降低螟加。

Block1.語法簡潔,實現(xiàn)回調(diào)不需要顯示的調(diào)用方法吞琐,代碼更為緊湊捆探。2.增強代碼的可讀性和可維護性。3.配合GCD優(yōu)秀的解決多線程問題站粟。1.Block中得代碼將自動進行一次retain操作黍图,容易造成內(nèi)存泄露2.Block內(nèi)默認引用為強引用,容易造成循環(huán)引用奴烙。

使用原則

如果方法過多助被,一般大于3個的時候,用delegate切诀,因為此時用block揩环,代碼將很難維護。比如UITableViewDelegate等等UI組建趾牧,都是用的delegate检盼。其他方式用block。

Notification能不用的時候盡量不用翘单,缺點太多明顯吨枉,增加調(diào)試難度。在工程大的情況下哄芜,極其難以維護貌亭。當然有些情況下也是必不可少的,比如觀察者模式.

感謝:向晨宇Block入門

Block測試題:http://blog.parse.com/learn/engineering/objective-c-blocks-quiz/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末认臊,一起剝皮案震驚了整個濱河市圃庭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌失晴,老刑警劉巖剧腻,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涂屁,居然都是意外死亡书在,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門拆又,熙熙樓的掌柜王于貴愁眉苦臉地迎上來儒旬,“玉大人栏账,你說我怎么就攤上這事≌辉矗” “怎么了挡爵?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長甚垦。 經(jīng)常有香客問我茶鹃,道長,這世上最難降的妖魔是什么制轰? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任前计,我火速辦了婚禮,結(jié)果婚禮上垃杖,老公的妹妹穿的比我還像新娘。我一直安慰自己丈屹,他們只是感情好调俘,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旺垒,像睡著了一般彩库。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上先蒋,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天骇钦,我揣著相機與錄音,去河邊找鬼竞漾。 笑死眯搭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的业岁。 我是一名探鬼主播鳞仙,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼笔时!你這毒婦竟也來了棍好?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤允耿,失蹤者是張志新(化名)和其女友劉穎借笙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體较锡,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡业稼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了念链。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盼忌。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡积糯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谦纱,到底是詐尸還是另有隱情看成,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布跨嘉,位于F島的核電站川慌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏祠乃。R本人自食惡果不足惜梦重,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亮瓷。 院中可真熱鬧琴拧,春花似錦、人聲如沸嘱支。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽除师。三九已至沛膳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汛聚,已是汗流浹背锹安。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倚舀,地道東北人叹哭。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像瞄桨,于是被迫代替她去往敵國和親话速。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容