Block 进阶
轉載自:http://www.cnblogs.com/xiaofeixiang/p/4666796.html
?
關于Block之前有一篇文章已經寫過一篇文章Object-C-代碼塊Block回顧,不過寫的比較淺顯,不能體現出Block在實際開發(fā)中的重要性,關于Block的基礎知識,可以參考之前的博客。在實際開發(fā)中Block在回調過程中的是非常適合開發(fā)使用,不管是蘋果的官方的接口還是一些第三方庫的接口中都用到了Block回調。很多情況下Block和GCD一起使用,最常見的場景的就是App去后臺取數據的過程中是需要時間,數據取成功之后我們才能更新UI頁面,這就是最常見的回調的方式,也可以通過Notification來做,如果是單個用Notification沒問題,如果請求比較多的情況的,代碼量會上一個級別。
Block回調
簡單的Block寫法,返回類型 ?Block名稱 ?參數,基本上符合方法的寫法,先看一個最簡單的Block寫法:
| 1 2 3 4 5 | int??(^blockDemo)(int?a,int?b)=^(int?a,int?b){ ????return?a+b; }; NSLog(@"BlockDemo的結果:%d",blockDemo(90,72)); |
最后的結果是162,簡單明了,很容易看懂,現在我們先通過UITableView展示后臺數據,效果如下:
ViewController中的代碼,簡單的實現了一下UITableView:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | - (UITableView *)tableView { ????if?(!_tableView) { ????????_tableView = [[UITableView alloc] ??????????????????????initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds) - 10, ???????????????????????????????????????????????CGRectGetHeight(self.view.bounds) - 64) ??????????????????????style:UITableViewStylePlain]; ????????_tableView.rowHeight = 40.0; ????????_tableView.sectionHeaderHeight = 0.0; ????????_tableView.sectionFooterHeight = 0.0; ????????_tableView.dataSource =?self; ????????_tableView.delegate =?self; ????} ????return?_tableView; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ ????return?[self.dataSource count]; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath?*)indexPath{ ????UITableViewCell? *cell=[[UITableViewCell alloc]init]; ????cell.textLabel.text=[self.dataSource objectAtIndex:indexPath.row]; ????return?cell; } |
通過FEDataService中的fetchData取出數據:
| 1 2 3 4 | -(NSMutableArray?*)fetchData{ ????NSMutableArray??*mutableArray=[[NSMutableArray?alloc]initWithObjects:@"博客園",@"FlyElephant",@"http://www.cnblogs.com/xiaofeixiang",@"iOS技術交流群:228407086",nil]; ????return?mutableArray; } |
Controller中的調用:
| 1 2 | self.dataService=[[FEDataService alloc]init]; self.dataSource=[self.dataService? fetchData]; |
當時從后臺取數據是需要時間的,而且網絡不一定能取出數據,這個時候就可以通過Block進行回調,在DataService中重新定義了一個fetchDataSource方法:
| 1 | -(void)fetchDataSource:(void(^)(NSMutableArray?*array,NSError?*error))fetchDataBlock; |
注意這里的Block傳參的寫法,fetchDataBlock相當于是參數名,前面的是類型,實現中加入了GCD
| 1 2 3 4 5 6 7 8 | -(void)fetchDataSource:(void?(^)(NSMutableArray?*,?NSError?*))fetchDataBlock{ ????dispatch_time_t? time=dispatch_time(DISPATCH_TIME_NOW,?NSEC_PER_SEC*(int64_t)1.0); ????dispatch_after(time,dispatch_get_main_queue() , ^{ ?????????NSMutableArray??*mutableArray=[[NSMutableArray?alloc]initWithObjects:@"博客園",@"FlyElephant",@"http://www.cnblogs.com/xiaofeixiang",@"iOS技術交流群:228407086",nil]; ????????fetchDataBlock(mutableArray,nil); ????}); ????? } |
Controller中進行回調同樣實現以上效果:
| 1 2 3 4 5 6 | [self.dataService fetchDataSource:^(NSMutableArray??*array,NSError?*error){ ????if?(!error) { ????????self.dataSource=array; ????????[self.tableView reloadData]; ????} }]; |
Block延伸
1.棧塊,堆塊和全局塊
定義一個塊的時候,其所占的內存區(qū)域是在棧中的,塊只在定義它的那個范圍有有效,我們可以先看一下下面的寫法:
| 1 2 3 4 5 6 7 8 9 10 11 | NSString??*string=@"博客園FlyElephant"; void??(^block)(); if?([string isEqualToString:@"iOS技術交流群:228407086"]) { ????block=^{ ????????NSLog(@"keso"); ????}; }else{ ????block=^{ ????????NSLog(@"http://www.cnblogs.com/xiaofeixiang"); ????}; } |
先定義了block,之后在判斷語句中對block進行賦值,最終棧中保存兩個塊的內存,在判斷語句之外調用block有可能會把分配給塊的內存覆蓋,最終造成的結果就是有的時候正確,被覆寫的時候就會造成程序崩潰,解決上面問題的方式我們可以通過block從棧內存中通過copy存儲在堆內存中,代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 | NSString??*string=@"博客園FlyElephant"; void??(^block)(); if?([string isEqualToString:@"iOS技術交流群:228407086"]) { ????block=[^{ ????????NSLog(@"keso"); ????}?copy]; }else{ ????block=[^{ ????????NSLog(@"http://www.cnblogs.com/xiaofeixiang"); ????}?copy]; } |
存儲在堆中的塊就變成了引用計算類型,當引用計數變成0在ARC的環(huán)境下的就會被系統(tǒng)回收,而棧中的內存是由系統(tǒng)自動回收的,所以第一段代碼穩(wěn)定性不能保證,還有一種是全局塊,將全局塊聲明在全局內存中,編譯期就已經確定,不需要每次用到的在棧中創(chuàng)建,全局塊的拷貝是一個空操作,所以全局塊不可能被系統(tǒng)回收。
2.通過typedef簡化代碼可讀性
Block回調中我們發(fā)現傳入一個塊的對象寫法有的時候看起來實在不是那么簡單明了,我們可以通過typedef簡化定義一個塊:
| 1 | typedef?void??(^FetchBlock)(NSMutableArray??*dataSouce,NSError??*error); |
DataService中方法就可以簡化了不少:
| 1 | -(void)fetchDataSourceSimple:(FetchBlock)block; |
實現代碼和之前的block實現一樣:
| 1 2 3 4 5 6 7 | -(void)fetchDataSourceSimple:(FetchBlock)block{ ????dispatch_time_t? time=dispatch_time(DISPATCH_TIME_NOW,?NSEC_PER_SEC*(int64_t)1.0); ????dispatch_after(time,dispatch_get_main_queue() , ^{ ????????NSMutableArray??*mutableArray=[[NSMutableArray?alloc]initWithObjects:@"博客園",@"FlyElephant",@"http://www.cnblogs.com/xiaofeixiang",@"iOS技術交流群:228407086",?nil]; ????????block(mutableArray,nil); ????}); } |
總結
- 上一篇: C#面试题汇总(未完成)
- 下一篇: Axis,axis2,Xfire以及cx