摘要
block的語(yǔ)法讓人很蛋疼谆级,但是如果好好理一下思路讼积,發(fā)現(xiàn)也沒(méi)那么難。
代理設(shè)計(jì)模式對(duì)于iOS開(kāi)發(fā)的人來(lái)說(shuō)肯定很熟悉了勤众,代理delegate就是委托另一個(gè)對(duì)象來(lái)幫忙完成一件事情,為什么要委托別人來(lái)做呢吕朵,這其實(shí)是MVC設(shè)計(jì)模式中的模塊分工問(wèn)題窥突,例如View對(duì)象它只負(fù)責(zé)顯示界面,而不需要進(jìn)行數(shù)據(jù)的管理梧税,數(shù)據(jù)的管理和邏輯是Controller的責(zé)任,所以此時(shí)View就應(yīng)該將這個(gè)功能委托給Controller去實(shí)現(xiàn)第队,當(dāng)然你作為碼農(nóng)強(qiáng)行讓View處理數(shù)據(jù)邏輯的任務(wù)煌茬,也不是不行,只是這就違背了MVC設(shè)計(jì)模式晾蜘,項(xiàng)目小還好,隨著功能的擴(kuò)展剔交,我們就會(huì)發(fā)現(xiàn)越寫越難寫;還有一種情況岖常,就是這件事情做不到,只能委托給其他對(duì)象來(lái)做了板惑,下面的例子中我會(huì)說(shuō)明這種情況偎快。
下面的代碼我想實(shí)現(xiàn)一個(gè)簡(jiǎn)單的功能,場(chǎng)景描述如下:TableView上面有多個(gè)CustomTableViewCell裆馒,cell上面顯示的是文字信息和一個(gè)詳情Button丐怯,點(diǎn)擊button以后push到一個(gè)新的頁(yè)面。為什么說(shuō)這個(gè)場(chǎng)景用到了代理delegate读跷?因?yàn)閎utton是在自定義的CustomTableViewCell上面,而cell沒(méi)有能力實(shí)現(xiàn)push的功能些膨,因?yàn)閜ush到新頁(yè)面的代碼是這樣的钦铺,
[self.navigationController pushViewController...];
所以這時(shí)候CustomTableViewCell就要委托它所在的Controller去做這件事情了肢预。
按照我的編碼習(xí)慣,我喜歡把委托的協(xié)議寫在提出委托申請(qǐng)的類的頭文件里面烫映,現(xiàn)在的場(chǎng)景中是CustomTableViewCell提出了委托申請(qǐng),下面是簡(jiǎn)單的代碼抽兆,
@protocolCustomCellDelegate
- (void)pushToNewPage;
@interfaceCustomTableViewCell :UITableViewCell
@property(nonatomic,assign)iddelegate;
@property(nonatomic,strong)UILabel *text1Label;
@property(nonatomic,strong) UIButton *detailBtn;
上面的代碼在CustomTableViewCell.h中定義了一個(gè)協(xié)議CustomCellDelegate族淮,它有一個(gè)需要實(shí)現(xiàn)的pushToNewPage方法凭涂,然后還要寫一個(gè)屬性修飾符為assign切油、名為delegate的property名惩,之所以使用assign是因?yàn)檫@涉及到內(nèi)存管理的東西,以后的博客中我會(huì)專門說(shuō)明原因娩鹉。
接下來(lái)在CustomTableViewCell.m中編寫B(tài)utton點(diǎn)擊代碼,
[self.detailBtnaddTarget:selfaction:@selector(btnClicked:)forControlEvents:UIControlEventTouchUpInside];
對(duì)應(yīng)的btnClicked方法如下巢株,
- (void)btnClicked:(UIButton*)btn
{
if(self.delegate&& [self.delegaterespondsToSelector:@selector(pushToNewPage)]) {
[self.delegatepushToNewPage];
}
}
上面代碼中的判斷條件最好是寫上熙涤,因?yàn)檫@是判斷self.delegate是否為空,以及實(shí)現(xiàn)CustomCellDelegate協(xié)議的Controller是否也實(shí)現(xiàn)了其中的pushToNewPage方法那槽。
接下來(lái)就是受到委托申請(qǐng)的類,這里是對(duì)應(yīng)CustomTableViewCell所在的ViewController骚灸,它首先要實(shí)現(xiàn)CustomCellDelegate協(xié)議慌植,然后要實(shí)現(xiàn)其中的pushToNewPage方法,還有一點(diǎn)不能忘記的就是要設(shè)置CustomTableViewCell對(duì)象cell的delegate等于self丈钙,很多情況下可能忘了寫cell.delegate = self;導(dǎo)致遇到問(wèn)題不知云里霧里交汤。下面的關(guān)鍵代碼都是在ViewController.m中,
首先是服從CumtomCellDelegate協(xié)議芙扎,這個(gè)大家肯定都知道,就像很多系統(tǒng)的協(xié)議俏橘,例如UIAlertViewDelegate、UITextFieldDelegate寥掐、UITableViewDelegate、UITableViewDatasource一樣曹仗。
@interfaceViewController()
@property(nonatomic,strong) NSArray *textArray;
然后是實(shí)現(xiàn)CustomCellDelegate協(xié)議中的pushToNewPage方法,
- (void)pushToNewPage
{
DetailViewController*detailVC = [[DetailViewControlleralloc] init];
[self.navigationControllerpushViewController:detailVCanimated:YES];
}
還有一個(gè)步驟最容易被忘記收壕,就是設(shè)置CumtomTableViewCell對(duì)象cell的delegate轨蛤,如下代碼,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
staticNSString*simpleIdentify =@"CustomCellIdentify";
CustomTableViewCell*cell = [tableViewdequeueReusableCellWithIdentifier:simpleIdentify];
if(cell ==nil) {
cell = [[CustomTableViewCellalloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:simpleIdentify];
}
//下面代碼很關(guān)鍵
cell.delegate=self;
cell.text1Label.text= [self.textArrayobjectAtIndex:indexPath.row];
returncell;
}
通過(guò)cell.delegate = self;確保了CustomTableViewCell.m的判斷語(yǔ)句if(self.delegate && ...){}中得self.delegate不為空圃验,此時(shí)的self.delegate其實(shí)就是ViewController缝呕,cell對(duì)象委托了ViewController實(shí)現(xiàn)pushToNewPage方法。這個(gè)簡(jiǎn)單的場(chǎng)景描述了使用代理的一種情況供常,就是CustomTableViewCell沒(méi)有能力實(shí)現(xiàn)pushViewController的功能,所以委托ViewController來(lái)實(shí)現(xiàn)麻裁。
代碼在github可以下載源祈。
有什么錯(cuò)誤,還請(qǐng)大家指正香缺。
----------------------------------------------下面是block的內(nèi)容----------------------------------------------------
Block是一個(gè)C語(yǔ)言的特性,就像群里有人說(shuō)的原献,它就是C語(yǔ)言的函數(shù)指針埂淮,在使用中最多的就是進(jìn)行函數(shù)回調(diào)或者事件傳遞,比如發(fā)送數(shù)據(jù)到服務(wù)器倔撞,等待服務(wù)器反饋是成功還是失敗慕趴,此時(shí)block就派上用場(chǎng)了鄙陡,這個(gè)功能的實(shí)現(xiàn)也可用使用代理躏啰,這么說(shuō)的話,感覺(jué)block是不是有點(diǎn)像代理了呢毫捣?
我之前接觸block,都是使用它作為函數(shù)參數(shù)蔓同,當(dāng)時(shí)感覺(jué)不是很理解《拙鳎現(xiàn)在在項(xiàng)目中,很多時(shí)候block作為property脯爪,這樣更加簡(jiǎn)單直接,想想咒锻,其實(shí)property不就是定義的合成存儲(chǔ)的變量嘛守屉,而block作為函數(shù)參數(shù)也是定義的變量,所以作為函數(shù)參數(shù)或者作為property本質(zhì)沒(méi)有區(qū)別拇泛。
看一看別人總結(jié)的block的語(yǔ)法吧,http://fuckingblocksyntax.com恭取,這個(gè)鏈接亮了熄守,fucking block syntax,操蛋的block語(yǔ)法啊裕照。block有如下幾種使用情況,
1惠猿、作為一個(gè)本地變量(local variable)
returnType(^blockName)(parameterTypes) = ^returnType(parameters) {...};
2、作為@property
@property (nonatomic, copy)returnType(^blockName)(parameterTypes);
3偶妖、作為方法的參數(shù)(method parameter)
- (void)someMethodThatTakesABlock:(returnType(^)(parameterTypes))blockName;
4、作為方法參數(shù)的時(shí)候被調(diào)用
[someObject someMethodThatTakesABlock: ^returnType(parameters) {...}];
5趾访、使用typedef來(lái)定義block,可以事半功倍
typedefreturnType(^TypeName)(parameterTypes);
TypeNameblockName = ^returnType(parameters) {...};
上面我也只是復(fù)制粘貼了一下屿聋,接下來(lái)還是實(shí)現(xiàn)點(diǎn)擊CustomTableViewCell上面的Button實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)的功能,我之前不止一次的類比block就像delegate润讥,這邊我也是思維慣性盘寡,下面的內(nèi)容我就當(dāng)block為代理,一些用詞描述還是跟delegate差不多脆粥。首先,在提出委托申請(qǐng)的CustomTableViewCell中定義block的property变隔,
@interfaceCustomTableViewCell :UITableViewCell
@property(nonatomic,strong)UILabel*text1Label;
@property(nonatomic,strong)UIButton*detailBtn;
//下面的定義蟹倾,請(qǐng)看官們對(duì)比一下
/*delegate的定義 我沒(méi)有刪除,因?yàn)榇蠹铱梢灶惐攘丝聪?/
@property(nonatomic,assign)id delegate;
/*這里定義了ButtonBlock*/
@property(nonatomic,copy)void(^ButtonBlock)();
@end
這里用copy屬性來(lái)修飾ButtonBlock property肌厨,這個(gè)原因,我會(huì)在以后的博客中作專門的解釋柑爸。
接下來(lái)在CustomTableViewCell中給它上面的detailBtn綁定點(diǎn)擊方法盒音,
[self.detailBtnaddTarget:selfaction:@selector(btnClicked:)forControlEvents:UIControlEventTouchUpInside];
然后是btnClicked方法的細(xì)節(jié),我把delegate的內(nèi)容也沒(méi)有刪除譬圣,就是給各位比較一下block和delegate的功能和語(yǔ)法的相似性,
- (void)btnClicked:(UIButton*)btn
{
//這是之前的delegate
if(self.delegate&& [self.delegaterespondsToSelector:@selector(pushToNewPage)]) {
[self.delegatepushToNewPage];
}
//這是現(xiàn)在我們要說(shuō)的block
if(ButtonBlock) {
ButtonBlock();
}
}
下面是一個(gè)關(guān)鍵性的地方胁镐,在ViewController2中設(shè)置其CustomTableViewCell的cell對(duì)象的ButtonBlock诸衔,也就是給它賦值,此處我還是保留了cell.delegate = self;代碼就缆,
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
NSString*blockIdentify =@"BlockIdentify";
CustomTableViewCell*cell = [tableViewdequeueReusableCellWithIdentifier:blockIdentify];
if(cell ==nil) {
cell = [[CustomTableViewCellalloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:blockIdentify];
}
cell.text1Label.text= [self.textArrayobjectAtIndex:indexPath.row];
//delegate的不可缺少的代碼谒亦,這里放在這兒只是為了給各位類比一下
cell.delegate=self;
//ButtonBlock不可缺少的代碼
cell.ButtonBlock = ^{
[selfpushToNewPage2];
};
returncell;
}
之所以cell.ButtonBlock = ^{};賦值,是因?yàn)槲覀兾覀兪沁@樣定義ButtonBlock的份招,void (^ButtonBLock)(),表示無(wú)返回值無(wú)參數(shù)廓旬。
然后編寫pushToNewPage2方法,
- (void)pushToNewPage2
{
DetailViewController*detailVC = [[DetailViewControlleralloc]init];
[self.navigationControllerpushViewController:detailVCanimated:YES];
}
你們看這個(gè)方法是不是與CustomCellDelegate協(xié)議中的pushToNewPage方法類似孕豹。然后在回過(guò)頭來(lái)類比一樣十气,是不是block就是精簡(jiǎn)版的delegate,因?yàn)閐elegate設(shè)計(jì)模式要寫協(xié)議CustomCellDelegate叶眉,還有容易遺漏cell.delegate = self;但是block使用的時(shí)候就簡(jiǎn)單多了。