標簽:ios? 代理? 模式? 協(xié)議? delegate??
閱讀前的知識儲備請確保在閱讀本文時洛口,曾經(jīng)不止一次親自動手敲過有關代理模式的代碼。如果沒有,請在積累一定的經(jīng)驗后閱讀冀墨,相信會更有收獲。也希望大神不吝指教涛贯。
什么時候要用協(xié)議和代理诽嘉?下面舉一個例子,談談個人對代理弟翘、協(xié)議的理解虫腋,希望能夠起到拋磚引玉的效果。假設現(xiàn)在有這么一個任務需求:頁面A需要跳轉到頁面B(有可能會傳入一些參數(shù))衅胀,頁面B填寫或者處理一些信息在跳轉回頁面A的同時還需要把數(shù)據(jù)返回A岔乔。不要為了用代理模式而用代理模式代理模式只是一種設計模式,它的價值在于通過一個統(tǒng)一的模式滚躯,解決一個原本并不方便雏门、甚至是幾乎不可能解決的問題嘿歌。也就是說當原來的、簡單的編程方式無法處理一個問題的時候茁影,才會想到運用一些設計模式(比如本文所談的代理模式)宙帝。舉個例子,如果說頁面A跳轉到頁面B需要傳遞參數(shù)募闲。顯然代理模式是可以用來傳參的步脓。但是這時候有沒有必要使用代理模式呢?我的回答是——“Never”浩螺。由于是從頁面A跳轉到頁面B靴患,那么代碼應該如下所示://AViewController.m@property (strong, nonatomic) BViewController *BVC;— (void)buttonDidClicked:(id)sender{? ? self.BVC = [[BViewController alloc]init];? ? [self.navigationController pushViewController:self.BVC animated:YES];}顯然B的viewController是作為A的viewController的一個屬性的。既然A有一個指向B的指針要出,那么直接通過指針去操作B即可鸳君。可以對B的屬性賦值患蹂,可以調用B的方法等等或颊。那么什么時候需要用到代理模式呢?我的回答是:“頁面B向頁面A傳值的時候”传于。答案也非常顯然囱挑,在頁面B中,我們甚至都不知道有頁面A的存在沼溜,向頁面A傳值就更是無從談起了平挑。那么此時一個可行的方案是,在頁面B中定義一個協(xié)議盛末,聲明一個代理對象弹惦。在頁面A中,將自己設置為頁面B的代理并且完成代理方法悄但。由此棠隐,不難得出一個結論:當一個對象無法直接獲取到另一個對象的指針,又希望對那個變量進行一些操作時檐嚣,可以使用代理模式助泽。代理模式到底做了什么?我眼中的代理模式只有兩個關注點:協(xié)議和代理者協(xié)議定義了一組方法嚎京,由某一個類負責實現(xiàn)嗡贺。 代理者作為某個類的一個屬性,通常是另一個類的實例對象鞍帝,可以負責完成原來這個類不方便或者無法完成的任務诫睬。首先談一談代理者,在腦中重新回想一下代理模式的實現(xiàn)過程帕涌。在頁面B中定義一個代理對象的時候摄凡,好像和定義一個普通的property非常類似(除了 weak和id《delegate》>)续徽。這也正是我對代理的概括:代理本來就是一個屬性而已,并沒有非常神秘亲澡。當然钦扭,代理者并不只是一個類普通的屬性,否則我只需要重寫一下B的初始化方法即可達到同樣的效果:self.BVC = [[BViewController alloc]initWithDelegate:self];然后在BViewController.m中定義一個AViewController *AVC并在初始化方法中賦值即可床绪。 注意到代理者在定義的時候客情,格式往往是這樣的:id<somedelegate>delegate;
所以我對代理的優(yōu)勢的理解是:
代理的核心優(yōu)勢在于解耦
與直接聲明一個屬于某個固定的類的代理者相比,聲明為id的代理者具備兩個明星的優(yōu)勢癞己。
允許多個不同的類成為本類的代理膀斋。試想一下在本文例子中,如果頁面B可以跳轉回N個頁面末秃,如果還是通過聲明一個普通對象的方式概页,那怎么辦籽御?
允許代理者的類還不固定练慕。試想一下,UITableView也有delegate技掏,它根本不知道那個類會成為它的代理者铃将。
再看一看協(xié)議。協(xié)議更加簡單了哑梳。協(xié)議只是定義了一組方法劲阎。在代理模式中,完全可以不用在頁面B中定義一個協(xié)議鸠真,然后A再去遵循這個協(xié)議悯仙。直接調用A的方法即可。
個人認為協(xié)議的優(yōu)點在于以下幾點:
可以利用Xcode的檢查機制吠卷。對于定義為@required的方法锡垄,如果實現(xiàn)了協(xié)議而沒有實現(xiàn)這個方法,編譯器將會有警告祭隔。這樣可以防止因為疏忽货岭,忘記實現(xiàn)某個代碼的情況,而由于OC的運行時特性疾渴,這樣的錯誤往往在運行階段才會導致程序崩潰千贯。
有利于代碼的封裝。如果一個類搞坝,實現(xiàn)了某個協(xié)議搔谴,那么這個協(xié)議中的方法不必在.h中被聲明,就可以被定義協(xié)議的類調用桩撮。這樣可以減少一個類暴露給外部的方法敦第。
有利于程序的結構化與層次化慌核。一個協(xié)議往往是解決問題的某個方法,對于一個其他的不過卻類似的問題申尼,我們只用再次實現(xiàn)協(xié)議即可垮卓,避免了自己再次構思一組方法。協(xié)議的繼承機制使得這一有點更加強大师幕。
說了怎么多粟按,總結起來只有一句:代理模式并不神秘,只是一個經(jīng)過了優(yōu)化的小技巧(讓某個類持有另一個類的指針)霹粥。代理和協(xié)議也只是讓程序耦合度更低灭将,結構感更強而已。