轉(zhuǎn)帖H陈濉玻募!
protocol和delegate完全不是一回事,放在一起說(shuō)滑肉,只是因?yàn)槲覀兘?jīng)常在同一個(gè)頭文件里看到這兩個(gè)word包各。
協(xié)議(protocol),就是使用了這個(gè)協(xié)議后就要按照這個(gè)協(xié)議來(lái)辦事靶庙,協(xié)議要求實(shí)現(xiàn)的方法就一定要實(shí)現(xiàn)问畅。
委托(delegate),顧名思義就是委托別人辦事六荒,就是當(dāng) 一件事情發(fā)生后护姆,自己不處理,讓別人來(lái)處理掏击。
舉個(gè)淺顯的例子:
我上班的工作主要內(nèi)容包括 (1)寫(xiě)代碼(2)寫(xiě)文檔(3)測(cè)試程序(4)接電話(huà)(5)會(huì)見(jiàn)客戶(hù)
(1)(2)我自己全權(quán)負(fù)責(zé)卵皂,但是后面(3)(4)(5)我不想或者不方便自己做,所以我想找個(gè)助手(delegate)幫我做這些事砚亭,于是我定了一個(gè)招聘要求(Protocol)灯变,里寫(xiě)明我的助手需要會(huì)做(3)(4)(5)這三件事。很快捅膘,我招到一個(gè)助手添祸。
即:我.delegate = 助手;
于是以后每當(dāng)我遇到需要測(cè)試程序或者接電話(huà)的活,我就把他轉(zhuǎn)交給助手(delegate)去處理篓跛,助手處理完后如果有處理結(jié)果(返回值)助手會(huì)告訴我膝捞,也許我會(huì)拿來(lái)用。如果不需要或者沒(méi)有結(jié)果愧沟,我就接著做下面的事蔬咬。。
protocol和java里interface的概念類(lèi)似沐寺,是Objective-C語(yǔ)法的一部分林艘。
定義protocol如下
@protocol?ClassADelegate
-?(void)methodA;
-?(void)methodB;
@end
那么就是定義了一組函數(shù),這組函數(shù)放在一起叫作一個(gè)protocol混坞,也就是協(xié)議狐援。
函數(shù)是需要被實(shí)現(xiàn)的钢坦,所以如果對(duì)于class如下
@interface?ClassB??{
}
@end
就叫作ClassB conform to protocol ClassADelegate,也就是說(shuō)ClassB實(shí)現(xiàn)了這個(gè)協(xié)議啥酱,
也就是實(shí)現(xiàn)了這一組函數(shù)爹凹。
有了上面這個(gè)頭文件,我們就可以放心作調(diào)用
ClassB?*b?=?[[ClassB?alloc]?init];
[b?methodA];
[b?methodB];
而不用擔(dān)心出現(xiàn)unrecognized selector sent to instance這種錯(cuò)誤了镶殷。
所以protocol就是一組函數(shù)定義禾酱,是從類(lèi)聲明中剝離出來(lái)的一組定義。
id?b?=?...;
[b?methodA];
這種用法也常見(jiàn)绘趋,b是一個(gè)id類(lèi)型颤陶,它知道ClassADelegate這組函數(shù)的實(shí)現(xiàn)。
那么delegate是什么陷遮?其實(shí)和protocol沒(méi)有關(guān)系滓走。Delegate本身應(yīng)該稱(chēng)為一種設(shè)計(jì)模式。
是把一個(gè)類(lèi)自己需要做的一部分事情帽馋,讓另一個(gè)類(lèi)(也可以就是自己本身)來(lái)完成搅方。
比如ClassC
@interface?ClassC?{
id?delegate;
}
@end
那么ClassC的實(shí)現(xiàn)(.m文件)里就可以用delegate這個(gè)變量了。
當(dāng)然這里完全可以用其它名字而不是delegate茬斧。
我們也可以這樣寫(xiě)
@interface?ClassC?{
ClassB?*delegate;
}
@end
這樣我們知道了delegate是一個(gè)ClassB腰懂,它就可以提供ClassB里的方法。
可以把一部分ClassC里的工作放在ClassB里去實(shí)現(xiàn)项秉。
這樣的寫(xiě)法看起來(lái)是不是有點(diǎn)奇怪绣溜?或者應(yīng)該寫(xiě)成這樣?
@interface?ClassC?{
ClassB?*classB;
}
@end
…
delegate沒(méi)有了…
所以說(shuō)其實(shí)delegate只是一種模式娄蔼,大家約定俗成怖喻,當(dāng)把自己內(nèi)部一部分實(shí)現(xiàn)暴露給另外一個(gè)類(lèi)去做的時(shí)候,就叫實(shí)際做事的類(lèi)為delegate岁诉。
為什么會(huì)需要把內(nèi)部實(shí)現(xiàn)提出來(lái)給另一個(gè)類(lèi)做呢锚沸?
最常見(jiàn)的目的就是為了在隱藏實(shí)現(xiàn)的前提下,提供一個(gè)自定義的機(jī)會(huì)涕癣。
比如Apple提供的iOS SDK里就有眾多的delegate哗蜈,比如最常用的UITableView,
我們沒(méi)法知道Apple怎么重用UITableViewCell坠韩,怎么處理UITableView里Cell的增加距潘、刪減,因?yàn)槲覀儧](méi)有源碼只搁。
但是我們可以通過(guò)實(shí)現(xiàn)Delegate的方法來(lái)控制一個(gè)UITableView的一些行為音比。
UITableViewDataSource其實(shí)和delegate是一樣一樣的,只是由于意義不同換了個(gè)名字罷了氢惋。
protocol在此扮演了什么角色呢洞翩?
protocol是一種語(yǔ)法稽犁,它提供了一個(gè)很方便的、實(shí)現(xiàn)delegate模式的機(jī)會(huì)骚亿。
比如寫(xiě)UITableView的時(shí)候已亥,Apple這么干
UITableView.m
-?(void)doSomething?{
[self?blahblah];
[self.delegate?guruguru];
[self?blahblah];
}
delegate是我們寫(xiě)的類(lèi),這個(gè)類(lèi)如果可以被傳給UITableView做為其delegate来屠,那唯一要求陷猫,就是它實(shí)現(xiàn)了
- (void)guruguru;
這個(gè)方法。
如果我們把這個(gè)方法定義在一個(gè)protocol里
@protocol?XXXProtocol
-?(void)guruguru;
@end
就說(shuō)明了的妖,UITableView需要的delegate是一個(gè)conform to XXXProtocol的類(lèi)。
這就正好是
id
表達(dá)的意思足陨。
無(wú)論具體的類(lèi)是什么嫂粟,它還有其它什么方法,只要它c(diǎn)onform to這個(gè)protocol墨缘,
就說(shuō)明它可以被傳給UITableView星虹,作為它的delegate。
那么Apple為了讓我們知道這個(gè)protocol是delegate需要conform的protocol镊讼,
它就把XXXProtocol改成了UITableViewDelegate
這樣我們看到protocol的名字里有Delegate宽涌,就知道這個(gè)protocol里的函數(shù)是用來(lái)做自定義(Customization)的了。
來(lái)源:http://haoxiang.org/2011/08/ios-delegate-and-protocol/
Protocol 的其它問(wèn)題
1. 使用時(shí)為什么要加上 iOS.delegate = self
物件名稱(chēng).delegate = self蝶棋,是在采用任何協(xié)定時(shí)
一定會(huì)看到的一行程式碼卸亮,由于定義協(xié)定的類(lèi)別并不需要實(shí)作協(xié)定內(nèi)的方法,因?yàn)閷?shí)作的部份是由采納協(xié)定的類(lèi)別來(lái)實(shí)作玩裙,但是它又必須要知道是由哪一個(gè)類(lèi)別來(lái)實(shí)
作兼贸,因此我們必須要把采納協(xié)定類(lèi)別的 instance 交給定義協(xié)定的類(lèi)別,讓它來(lái)使用吃溅。
另一方面并不是任何類(lèi)別都可以將 instance 傳給定義協(xié)定的類(lèi)別來(lái)使用溶诞,其原因是,我們?cè)诙x此協(xié)定的類(lèi)別里有宣告 delegate
變數(shù)時(shí)决侈,有限定它必須要采納此協(xié)定(id delegate)如果沒(méi)有采用該協(xié)定就將 instance 傳給定義該協(xié)定的類(lèi)別螺垢,Xcode
同樣會(huì)發(fā)出警告訊息。
2. 為什么協(xié)定的生效位置不能寫(xiě)在建構(gòu)式中
協(xié)定的生效位置寫(xiě)在建構(gòu)式中赖歌,并不會(huì)造成程式編譯上的任何問(wèn)題枉圃,因?yàn)檫@是屬于邏輯上的錯(cuò)誤,協(xié)定要正常生效它必須要知道實(shí)作它方法的類(lèi)別的
instance俏站,如果將生效的位置寫(xiě)在建構(gòu)式中讯蒲,在建立定義此協(xié)定的形態(tài)的變物件時(shí),它的確會(huì)去觸發(fā)此協(xié)定內(nèi)的方法肄扎,但是由于并沒(méi)有給它實(shí)作此協(xié)定方法
類(lèi)別的 instance墨林,因此不會(huì)有任何效果產(chǎn)生赁酝,反之,如果一定要將生效的位置寫(xiě)在建構(gòu)式中旭等,那么在初始化時(shí)就必須要設(shè)定好 delegate
才行酌呆,也就是使用初始化的方法函式里還必須要帶入一個(gè)參數(shù)物件好指定給 delegate。
3. 在定義協(xié)定時(shí)同時(shí)也可以采用其他的協(xié)定
如果在定義協(xié)定時(shí)同時(shí)又採(cǎi)用其他的協(xié)定搔耕,這會(huì)導(dǎo)致之后採(cǎi)納此協(xié)定的類(lèi)別,它必須同時(shí)實(shí)作出兩個(gè)協(xié)定內(nèi)的方法弃榨,同樣地菩收,你也可以利用此方式來(lái)擴(kuò)充那些已經(jīng)存在的協(xié)定。
@protocol?FurnaceDelegate?<其它可能的協(xié)定名稱(chēng)>
4. 使用 @optional 提供選擇性的實(shí)作
@optional鲸睛,如同它字面上的意義娜饵,在 @optional 之后的方法都可以是選擇性的實(shí)作,在定義協(xié)定時(shí)使用此方法官辈,可以讓之后採(cǎi)納此協(xié)定的類(lèi)別不一定要完全實(shí)作出協(xié)定內(nèi)的所有方法箱舞。
@protocol?FurnaceDelegate
-?(void)whenCalledDelegeteFunction;
@optional
-(void)optionalDelegeteFunction;
@end
來(lái)源:http://furnacedigital.blogspot.com/2012/01/protocol.html