iOS 之 Protocol 詳解

iOS開發(fā)中减俏,Protocol是一種經(jīng)常用到的設(shè)計(jì)模式,蘋果的系統(tǒng)框架中也普遍用到了這種方式战转,比如UITableView中的<UITableViewDelegate>痛黎,以及<NSCopying>予弧、<NSObject>這樣的協(xié)議。我想大家也都自定義過協(xié)議湖饱,一般都用于回調(diào)掖蛤,或者數(shù)據(jù)傳遞。不過井厌,用久了以后蚓庭,不知道大家是否會(huì)有一些困惑:協(xié)議只能用于委托代理嗎?為什么系統(tǒng)中定義了這么多協(xié)議仅仆?為什么感覺分類和協(xié)議好像器赞?系統(tǒng)中又為何會(huì)定義這么多分類?被這些問題轟炸后墓拜,我不禁又開始想拳魁,協(xié)議到底是個(gè)啥玩意?

帶著這樣的目地撮弧,我閱讀了一些文檔書籍潘懊,最后整理了以下的內(nèi)容:

  • protocol是什么?
  • protocol里有些啥?
  • protocol可以寫在哪?
  • protocol里的方法由誰實(shí)現(xiàn)姚糊,由誰調(diào)用?
  • protocol分類:正式協(xié)議和非正式協(xié)議?
  • protocol有哪些作用授舟,能用在哪些地方?

1. protocol 是什么?

iOS 開發(fā)文檔是這樣定義的:(翻譯略渣救恨,請(qǐng)見諒)

A protocol declares a programmatic interface that any class may choose to implement. Protocols make it possible for two classes distantly related by inheritance to communicate with each other to accomplish a certain goal. They thus offer an alternative to subclassing. Any class that can provide behavior useful to other classes may declare a programmatic interface for vending that behavior anonymously. Any other class may choose to adopt the protocol and implement one or more of its methods, thereby making use of the behavior. The class that declares a protocol is expected to call the methods in the protocol if they are implemented by the protocol adopter.

協(xié)議聲明了任何類都能夠選擇實(shí)現(xiàn)的程序接口。協(xié)議能夠使兩個(gè)不同繼承樹上的類相互交流并完成特定的目的释树,因此它提供了除繼承外的另一種選擇肠槽。任何能夠?yàn)槠渌愄峁┯杏眯袨榈念惗寄軌蚵暶鹘涌趤砟涿膫鬟_(dá)這個(gè)行為。任何其他類都能夠選擇遵守這個(gè)協(xié)議并實(shí)現(xiàn)其中的一個(gè)或多個(gè)方法奢啥,從而利用這個(gè)行為秸仙。如果協(xié)議遵守者實(shí)現(xiàn)了協(xié)議中的方法,那么聲明協(xié)議的類就能夠通過遵守者調(diào)用協(xié)議中的方法桩盲。

2. protocol 里有些啥?

協(xié)議中能夠聲明方法寂纪,以及屬性。然后問題就來了赌结,不是不能定義成員變量的嗎捞蛋?

對(duì),的確不能定義成員變量柬姚,但是屬性是什么拟杉?屬性包含了三個(gè)東西:成員變量、setter方法量承、getter方法搬设。在類中定義的屬性,當(dāng)然三者都有撕捍,然而協(xié)議中定義的屬性只有獲取和設(shè)置方法拿穴,沒有成員變量,這就要求該協(xié)議的遵守者必須自己寫出settergetter方法的實(shí)現(xiàn)卦洽。但是有一種情況是不需要的,那就是遵守者本來就有這個(gè)屬性斜棚,此時(shí)系統(tǒng)會(huì)為這個(gè)屬性自動(dòng)生成設(shè)置獲取方法阀蒂,既然已經(jīng)實(shí)現(xiàn)了,那么遵守者就沒必要去實(shí)現(xiàn)協(xié)議中的這個(gè)屬性了弟蚀。

盡管可以實(shí)現(xiàn)“偽屬性”蚤霞,但是,我們還是應(yīng)該盡量把屬性定義在主接口中义钉,而不應(yīng)該定義在協(xié)議中昧绣。

還有一點(diǎn),也是很重要的一點(diǎn)捶闸,為什么自定義的協(xié)議后面會(huì)有這么一個(gè)東西<NSObject>?

協(xié)議也能繼承夜畴。既可以繼承自自定義的協(xié)議拖刃,也可以繼承自系統(tǒng)的協(xié)議。
我們?cè)诙x協(xié)議的時(shí)候贪绘,一般都是直接繼承自<NSObject>兑牡,為什么系統(tǒng)要默認(rèn)讓協(xié)議繼承自這個(gè)協(xié)議呢?

因?yàn)檫@個(gè)協(xié)議中定義了一些基本的方法税灌,由于我們使用的所有類都繼承NSObject這個(gè)基類均函,而這個(gè)基類遵守了<NSObject>這個(gè)協(xié)議,那么也就實(shí)現(xiàn)了其中的那些方法菱涤,這些方法當(dāng)然可以由NSObject及其子類對(duì)象調(diào)用苞也,但是在不知道遵守者類型的時(shí)候需要用到id <協(xié)議名>這樣的指針,這個(gè)指針在編譯期并不知道自己指向哪個(gè)對(duì)象粘秆,唯一能調(diào)用的便是協(xié)議中的方法如迟,然而有時(shí)候又需要用一些基本的方法,比如要辨別id <協(xié)議名>這個(gè)指針?biāo)傅膶?duì)象屬于哪個(gè)類翻擒,就要用到-isMemberOf:這個(gè)方法氓涣,而這個(gè)方法是<NSObject>這個(gè)協(xié)議中的方法之一,所以陋气,我們自定義的協(xié)議都需要繼承<NSObject>劳吠。本段一開始便說道:<NSObject>中的方法在NSObject基類中實(shí)現(xiàn)了,那么無需再關(guān)心實(shí)現(xiàn)了巩趁,直接調(diào)用<NSObject>中的方法吧痒玩。

3. protocol 可以寫在哪?

寫在頭文件中议慰,寫在實(shí)現(xiàn)文件的類擴(kuò)展中蠢古。

前者:可以當(dāng)做是給這個(gè)類添加了一些外部接口。
后者:可以當(dāng)做是給這個(gè)類添加了一些私有接口别凹。

  • 寫在頭文件中草讶,類內(nèi)部自然能通過self調(diào)用,外部也可以調(diào)用里面的方法炉菲,子類可以實(shí)現(xiàn)或者重寫里面的方法堕战。
  • 而在類擴(kuò)展中,內(nèi)部可以調(diào)用拍霜,外部不能調(diào)用嘱丢、子類不能重寫實(shí)現(xiàn)和重寫,相當(dāng)于是私有方法祠饺。

不過越驻,如果子類自身又遵循了這個(gè)協(xié)議,但并沒有實(shí)現(xiàn),那么在運(yùn)行時(shí)缀旁,系統(tǒng)會(huì)一級(jí)級(jí)往上查找记劈,直到找到父類的方法實(shí)現(xiàn)。也就是說诵棵,只要知道蘋果的私有方法名抠蚣,并且確保自己的類是這個(gè)私有方法所屬類的子類,就可以在子類中通過只聲明不實(shí)現(xiàn)的方式執(zhí)行父類中該私有方法的實(shí)現(xiàn)履澳。

4. protocol 里的方法由誰實(shí)現(xiàn)嘶窄,由誰調(diào)用

實(shí)現(xiàn):遵守協(xié)議者及其子類
調(diào)用:遵守協(xié)議者、其子類距贷、id <協(xié)議名>

5. protocol 的分類:正式協(xié)議 和 非正式協(xié)議(類別)

iOS 文檔是這樣定義的:

There are two varieties of protocol, formal and informal:

A formal protocol declares a list of methods that client classes are expected to implement. Formal protocols have their own declaration, adoption, and type-checking syntax. You can designate methods whose implementation is required or optional with the @required and @optional keywords. Subclasses inherit formal protocols adopted by their ancestors. A formal protocol can also adopt other protocols. Formal protocols are an extension to the Objective-C language.

An informal protocol is a category on NSObject, which implicitly makes almost all objects adopters of the protocol. (A category is a language feature that enables you to add methods to a class without subclassing it.) Implementation of the methods in an informal protocol is optional. Before invoking a method, the calling object checks to see whether the target object implements it. Until optional protocol methods were introduced in Objective-C 2.0, informal protocols were essential to the way Foundation and AppKit classes implemented delegation.

  • 正式協(xié)議聲明了一系列需要遵守協(xié)議者實(shí)現(xiàn)的方法柄冲。正式協(xié)議擁有它們特有的聲明,遵守忠蝗,類型判斷的語法现横。你可以通過@required@optional關(guān)鍵詞來指定哪些方法是必須實(shí)現(xiàn)的以及哪些方法選擇實(shí)現(xiàn)。子類繼承父類遵守的協(xié)議阁最,正式協(xié)議也可以遵守其他協(xié)議戒祠。

  • 非正式協(xié)議是基于NSObject的類目,其所有子類都含蓄地遵守了這個(gè)協(xié)議(類目是一種語言特性速种,它能夠不用繼承便為類添加方法)在非正式協(xié)議中的方法是可以選擇實(shí)現(xiàn)的姜盈。在調(diào)用一個(gè)方法之前,調(diào)用者要確認(rèn)目標(biāo)對(duì)象是否實(shí)現(xiàn)了方法配阵。在OC 2.0引入可選正式協(xié)議方法之前馏颂,非正式協(xié)議是FoundationAppKit框架中的類中實(shí)現(xiàn)委托的唯一方式。

類目實(shí)際上是一種特殊的協(xié)議棋傍。我們沒法通過正式協(xié)議為系統(tǒng)的類添加方法救拉,因?yàn)槲覀儫o法編輯系統(tǒng)的類。當(dāng)然瘫拣,我們也可以選擇繼承的方式亿絮,但是,這就會(huì)創(chuàng)建一個(gè)新的類麸拄,并不是特別劃算派昧。所以,類目這種方式派上用場(chǎng)了感帅。

但是為什么系統(tǒng)框架中使用了這么多的類目呢斗锭?設(shè)計(jì)者當(dāng)初為什么不把類目中的方法寫到主接口中地淀?

原因在于要將眾多的方法打散到各處失球,要將同一類型功能的接口都封裝在一個(gè)類目中。這樣做能夠減少主接口中的代碼量,也便于調(diào)試实苞。我們還可以把類中的私有方法全部封裝在名為Private的類目中豺撑,然后在實(shí)現(xiàn)文件中引入這個(gè)類目,這樣做可以把共有的方法定義在一個(gè)類目中黔牵,也很容易能夠清楚哪些是私有方法聪轿。

協(xié)議,尤其是類目猾浦,一定要給類目的名稱和方法名添加自己的特有前綴陆错,這樣做既不會(huì)和系統(tǒng)的類目沖突,也不會(huì)在將自己的代碼開源后和其他使用者的類目沖突金赦。

6. protocol 有哪些作用音瓷,用在哪些地方

  • 某一個(gè)類需要委托其他類處理某些事件,最具代表性性的便是UITableView的那些代理方法夹抗。這些方法其實(shí)還是代理的方法绳慎,只不過定義的地方可能會(huì)在委托者類中,通過調(diào)用這些方法漠烧,可以:將委托者中的數(shù)據(jù)傳遞給代理杏愤;將代理的數(shù)據(jù)傳遞給委托者;將委托者的事件拋給代理去處理...

  • 給某幾個(gè)特定的類添加統(tǒng)一的接口已脓,這些接口是從這些類中抽象出的共同的行為珊楼,這樣便可以減少重復(fù)的代碼。

總結(jié)

協(xié)議就是定義公共接口的地方摆舟,只要遵守協(xié)議亥曹,就等于在頭文件中定義了這些方法,只要實(shí)現(xiàn)就行了恨诱。之所以有這樣的設(shè)計(jì)媳瞪,是因?yàn)橐獙⒐餐男袨槌橄蟪鰜恚翰煌念愑胁煌淖饔煤吞卣鳎@也是面向?qū)ο蟮奶攸c(diǎn)照宝,但是即使千差萬別蛇受,還是會(huì)有某些相似點(diǎn)的,這些相似的地方就可以抽象出來做成協(xié)議厕鹃。但有時(shí)候這些共同的部分并不是本身就有的兢仰,而是人為的添加的,我們要求這些類具有共同的部分剂碴,而不管這些類是多么千差萬別把将。有人會(huì)問,為什么不寫一個(gè)公共的父類呢忆矛?子類繼承父類察蹲,這樣就能共有某些方法了请垛?

當(dāng)然是有這樣的設(shè)計(jì)的,Foundation框架下類的設(shè)計(jì)就是這樣一層一層寫下去的洽议,最具相同性的屬性和方法聲明的位置絕對(duì)更靠前宗收。但是,如果同時(shí)需要遵守協(xié)議的是來自兩個(gè)不同繼承樹上的類呢亚兄?難道是找到它們共有的祖先類混稽,然后把方法寫在那里面嗎?顯然這么做是不行的审胚,因?yàn)檫@樣會(huì)導(dǎo)致兩個(gè)繼承樹下的所有子類都可以調(diào)用匈勋,然而并不是所有子類都需要這些方法,所以還是得要用協(xié)議膳叨。

很多人會(huì)看到有一個(gè)<NSObject>的協(xié)議颓影,這個(gè)協(xié)議和NSObject這個(gè)類同名,由NSObject遵守懒鉴,為什么不把這些方法直接寫到NSObject類中呢诡挂?因?yàn)?code>cocoa框架中的基類不止NSObject一個(gè),還有NSProxy這樣的類存在临谱,那么<NSObject>這個(gè)協(xié)議就很容易明白了璃俗,它抽象出了所有基類都需要的方法,為基類提供共有方法悉默。還有一個(gè)原因的話城豁,在上文中已經(jīng)說明了,自定義的類要繼承自這個(gè)協(xié)議抄课,以供匿名對(duì)象id<協(xié)議名>使用唱星。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市跟磨,隨后出現(xiàn)的幾起案子间聊,更是在濱河造成了極大的恐慌,老刑警劉巖抵拘,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哎榴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡僵蛛,警方通過查閱死者的電腦和手機(jī)尚蝌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來充尉,“玉大人飘言,你說我怎么就攤上這事⊥障溃” “怎么了姿鸿?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵泵喘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我般妙,道長(zhǎng),這世上最難降的妖魔是什么相速? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任碟渺,我火速辦了婚禮,結(jié)果婚禮上突诬,老公的妹妹穿的比我還像新娘苫拍。我一直安慰自己,他們只是感情好旺隙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布绒极。 她就那樣靜靜地躺著,像睡著了一般蔬捷。 火紅的嫁衣襯著肌膚如雪垄提。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天周拐,我揣著相機(jī)與錄音铡俐,去河邊找鬼。 笑死妥粟,一個(gè)胖子當(dāng)著我的面吹牛审丘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勾给,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼滩报,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了播急?” 一聲冷哼從身側(cè)響起脓钾,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桩警,沒想到半個(gè)月后惭笑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡生真,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年沉噩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柱蟀。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡川蒙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出长已,到底是詐尸還是另有隱情畜眨,我是刑警寧澤昼牛,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站康聂,受9級(jí)特大地震影響贰健,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恬汁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一伶椿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氓侧,春花似錦脊另、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至独郎,卻和暖如春踩麦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氓癌。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工靖榕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人顽铸。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓茁计,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親谓松。 傳聞我的和親對(duì)象是個(gè)殘疾皇子星压,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,721評(píng)論 0 9
  • 1.項(xiàng)目經(jīng)驗(yàn) 2.基礎(chǔ)問題 3.指南認(rèn)識(shí) 4.解決思路 ios開發(fā)三大塊: 1.Oc基礎(chǔ) 2.CocoaTouch...
    陽(yáng)光的大男孩兒閱讀 4,988評(píng)論 0 13
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,150評(píng)論 30 470
  • 132.轉(zhuǎn)換錯(cuò)誤成可選值 通過轉(zhuǎn)換錯(cuò)誤成一個(gè)可選值,你可以使用 try? 來處理錯(cuò)誤鬼譬。當(dāng)執(zhí)行try?表達(dá)式時(shí),如果...
    無灃閱讀 1,257評(píng)論 0 3
  • t Running. His work has been translated into more than fo...
    夏至末日閱讀 169評(píng)論 0 0