[置頂] block一點也不神祕————如何利用block進行回調

咱們在開發中經常會用到函數回調,你能夠用通知來替代回調,可是大多數時候回調是比通知方便的,因此何樂而不爲呢?若是你不知道回調使用的場景,咱們來假設一下:app

1.我如今玩手機函數

2.忽然手機沒有電了spa

3.我只好讓手機開始充電.net

4.充電的過程當中我好無聊,我要去看電視,可是我不會一直看電視,我要等手機電充滿了中止看電視,繼續去玩手機線程

5.我開始看電視指針

6.手機電充好了,我聽到手機響了一下,我不看電視了我繼續去玩手機。orm


這個場景中哪裏跟回調相似呢?哪裏跟通知相似呢?其實咱們能夠認爲手機充好電了經過回調的方式讓我繼續玩手機,也能夠認爲手機充好電了通知我能夠繼續玩手機,而後我主動繼續玩手機。這裏更像通知不像回調。可是換個思惟想,若是手機自己沒有回調機制,那他怎麼能在剛好手機剛充滿的時候響一下呢?blog

先不糾結這個問題,咱們看看若是用block怎樣來實現這樣一個場景:事件

咱們隨便找個控制器寫下如下代碼:ip

[cpp] view plain copy

 print?

  1. <span style="font-family:Comic Sans MS; font-size:18px">- (void)viewDidLoad  

  2. {  

  3.     [super viewDidLoad];  

  4.     // Do any additional setup after loading the view.  

  5.     NSLog(@"我在玩手機");  

  6.     NSLog(@"手機沒電了");  

  7.     [self chargeMyIphone];  

  8.     NSLog(@"我在看電視");  

  9.       

  10.      

  11.   

  12.       

  13. }  

  14. -(void)chargeMyIphone  

  15. {  

  16.     [NSThread sleepForTimeInterval:10];  

  17.     NSLog(@"電充好了");  

  18. }</span>  

注意 這裏我用了NSTread sleep,這樣會讓個人主線程沉睡10秒鐘,這個過程當中我我真的能夠一邊看電視一邊充電嗎?




因此咱們應該讓充電的線程和我看電視的線程錯開執行!這裏咱們就不開新線程了,就讓他10秒以後再執行吧。模擬下:


[cpp] view plain copy

 print?

  1. <span style="font-family:Comic Sans MS; font-size:18px">- (void)viewDidLoad  

  2. {  

  3.     [super viewDidLoad];  

  4.     // Do any additional setup after loading the view.  

  5.     NSLog(@"我在玩手機");  

  6.     NSLog(@"手機沒電了");  

  7.     [self performSelector:@selector(chargeMyIphone:) withObject:Nil afterDelay:10];  

  8.   

  9.     NSLog(@"我在看電視");  

  10.       

  11.      

  12.   

  13.       

  14. }  

  15. </span>  

改一下這一句代碼後,咱們再看看:

2013-09-17 00:47:54.786 故事版應用[1013:a0b]我在玩手機

2013-09-17 00:47:54.787 故事版應用[1013:a0b]手機沒電了

2013-09-17 00:47:54.787 故事版應用[1013:a0b]我在看電視

2013-09-17 00:48:04.799 故事版應用[1013:a0b]電充好了

看起來沒多大問題,可是咱們還沒寫完咱們的場景呢,咱們想充好電以後繼續玩手機?因此咱們寫在哪兒呢?

若是直接放在看電視後面:

 NSLog(@"繼續玩手機");

咱們看看控制檯:

2013-09-17 00:50:12.417 故事版應用[1029:a0b]我在玩手機

2013-09-17 00:50:12.418 故事版應用[1029:a0b]手機沒電了

2013-09-17 00:50:12.419 故事版應用[1029:a0b]我在看電視

2013-09-17 00:50:12.419 故事版應用[1029:a0b]繼續玩手機

2013-09-17 00:50:22.431 故事版應用[1029:a0b]電充好了

呵呵!電都沒充好,你就直接繼續玩了?因此這裏應該是電充好之後 咱們再繼續玩手機?

那麼該怎麼作?咱們能夠寫進充電函數裏嗎?

[cpp] view plain copy

 print?

  1. <span style="font-family:Comic Sans MS; font-size:18px">-(void)chargeMyIphone  

  2. {  

  3.     NSLog(@"電充好了");  

  4.      NSLog(@"繼續玩手機");  

  5. }</span>  


咱們看看控制檯:

2013-09-17 00:51:43.832 故事版應用[1044:a0b]我在玩手機

2013-09-17 00:51:43.833 故事版應用[1044:a0b]手機沒電了

2013-09-17 00:51:43.833 故事版應用[1044:a0b]我在看電視

2013-09-17 00:51:53.848 故事版應用[1044:a0b]電充好了

2013-09-17 00:51:53.849 故事版應用[1044:a0b]繼續玩手機

看起來沒多大問題啊!可是咱們想一想看,咱們把繼續玩手機這件事情寫在了充電函數的最後?

若是說我每次衝完電都繼續玩手機,這個沒什麼問題!可是若是我每次衝完電以後不老是玩手機怎麼辦呢?

好比有一次我充完電以後想出門逛街!這個很好理解吧,那麼這樣寫就不對了!咱們想讓充電函數最後執行的那一行是能夠變化的。有不少方式能夠作到,可是這裏最好的作法確定是追加一個block替換掉咱們寫死的那句代碼啦!

也就是說我在充電前已經安排好一個充電後的計劃了,今天衝完電繼續玩手機,明天衝完電出門逛街,那麼我每次調用的仍是那個充電函數,只是傳的參數不同而已!咱們不用傳int 1表示玩手機,2表示出門逛街,咱們直接把這兩件事情當作參數傳過去!

明白這一點就知道block的最終奧義啦!因此咱們該改造一下這個函數,爲他加個包含代碼的參數!

[cpp] view plain copy

 print?

  1. <span style="font-family:Comic Sans MS; font-size:18px">-(void)chargeMyIphone:(void(^)(void))finishBlock  

  2. {  

  3.       NSLog(@"電充好了");  

  4.     //NSLog(@"繼續玩手機");  

  5.     finishBlock();  

  6. }</span>  


這個追加的參數就是咱們的block了,第一個void表示此block無返回值。(^)爲block type的標誌。第二個(void)表示這個block無參數。finishBlock就是他的名字。無參數無返回類型的匿名函數就是咱們的最簡單的block了!他很是方便咱們用來回調,由於他沒有返回值,沒有參數,就至關於只有內部的可執行代碼!

而咱們將一個固定的事件用一段代碼做爲參數傳了進來,而且以  名字() 形式來觸發它,那麼這個函數的結尾就不會老是玩手機了!那麼他能夠是任何事情!

因此咱們來嘗試調用下這個函數:


可是這裏的參數咱們該怎麼傳呢?咱們經過這種方式傳block參數好像不符合他這的object,因此咱們仍是直接調吧,可是把這一行用dispatch_after包起來~


按一下回車:


而後在中間寫我要作什麼,這裏是出門逛街;


接下來在chargeIphone內部敲dis,而後聯想出來選擇第一個按回車:


而後將時間改成10,把整個方法內的代碼移動進去:

[cpp] view plain copy

 print?

  1. <span style="font-family:Comic Sans MS; font-size:18px">- (void)viewDidLoad  

  2. {  

  3.     [super viewDidLoad];  

  4.     // Do any additional setup after loading the view.  

  5.     NSLog(@"我在玩手機");  

  6.     NSLog(@"手機沒電了");  

  7.      

  8.     [self chargeMyIphone:^{  

  9.         NSLog(@"出去逛街");  

  10.     }];  

  11.     NSLog(@"我在看電視");  

  12. }  

  13. -(void)chargeMyIphone:(void(^)(void))finishBlock  

  14. {  

  15.     double delayInSeconds = 10.0;  

  16.     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));  

  17.     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){  

  18.         NSLog(@"電充好了");  

  19.         finishBlock();  

  20.     });  

  21.       

  22. }</span>  


如今代碼的結構很是清晰:

充電完成以後 我要去逛街。

充電內部須要耗時10秒。

充電的同時我能夠看電視。

充電完成以後回頭來觸發我block中設置的出去逛街。


這樣設置block的好處我已經說過了,咱們沒有把充電函數內部的實現寫死,也就是說當我完成以後不管作什麼都無所謂,調的地方不一樣,傳不一樣的代碼過去就能夠了,這個跟函數指針相似吧。

咱們來運行一下程序驗證下最後的結果:

2013-09-17 01:17:23.127 故事版應用[1088:a0b]我在玩手機

2013-09-17 01:17:23.129 故事版應用[1088:a0b]手機沒電了

2013-09-17 01:17:23.129 故事版應用[1088:a0b]我在看電視

2013-09-17 01:17:33.130 故事版應用[1088:a0b]電充好了

2013-09-17 01:17:33.131 故事版應用[1088:a0b]出去逛街


徹底驗證了咱們的結論,23秒開始充電 ,看電視,33秒的適合充好電出去逛街。

OK ,最簡單的block咱們就講到這裏,用好他來給你的代碼非寫死吧!DON'T HARD WRITE

相關文章
相關標籤/搜索