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