概述
代理模式是一種消息傳遞方式,一個(gè)完整的代理模式包括:委托對(duì)象、代理對(duì)象和協(xié)議。
名詞解釋
- 協(xié)議:用來(lái)指定代理雙方可以做什么,必須做什么。
- 委托對(duì)象:根據(jù)協(xié)議指定代理對(duì)象需要完成的事,即調(diào)用協(xié)議中的方法。
- 代理對(duì)象:根據(jù)協(xié)議實(shí)現(xiàn)委托方需要完成的事,即實(shí)現(xiàn)協(xié)議中的方法。
1.Protocol-協(xié)議
從上圖中我們可以看到三方之間的關(guān)系,在實(shí)際應(yīng)用中通過(guò)協(xié)議來(lái)規(guī)定代理雙方的行為,協(xié)議中的內(nèi)容一般都是方法列表,當(dāng)然也可以定義屬性,我會(huì)在后續(xù)文章中順帶講一下協(xié)議中定義屬性。
協(xié)議是公共的定義,如果只是某個(gè)類使用,我們常做的就是寫(xiě)在某個(gè)類中。如果是多個(gè)類都是用同一個(gè)協(xié)議,建議創(chuàng)建一個(gè)Protocol文件,在這個(gè)文件中定義協(xié)議。遵循的協(xié)議可以被繼承,例如我們常用的UITableView,由于繼承自UIScrollView的緣故,所以也將UIScrollViewDelegate繼承了過(guò)來(lái),我們可以通過(guò)代理方法獲取UITableView偏移量等狀態(tài)參數(shù)。
協(xié)議只能定義公用的一套接口,類似于一個(gè)約束代理雙方的作用。但不能提供具體的實(shí)現(xiàn)方法,實(shí)現(xiàn)方法需要代理對(duì)象去實(shí)現(xiàn)。協(xié)議可以繼承其他協(xié)議,并且可以繼承多個(gè)協(xié)議,在iOS中對(duì)象是不支持多繼承的,而協(xié)議可以多繼承。
@interface TMGameViewControllerNew ()<ILVLiveAVListener,ILVLiveIMListener,AVAudioPlayerDelegate,TMGameViewModelDelegate,TMGameShowViewProcotol,TMGameControlViewDelegate,QAVChangeDelegate,CAAnimationDelegate,TMMsgTooBarDelegate,UINavigationControllerDelegate>{
NSInteger _chargeSource;
BOOL _firstComeRoom;
BOOL _firstGuideCamera;
}
2.委托對(duì)象
if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) {
// 調(diào)用代理對(duì)象的登錄方法,代理對(duì)象去實(shí)現(xiàn)登錄方法
[self.delegate userLoginWithUsername:self.username.text password:self.password.text];
}
3.代理對(duì)象
self.gameView = [[TMGameView alloc]initWithFrame:self.view.frame parentVC:self viewModel:self.gameViewModel];
self.gameView.avIsLoad = NO;
self.gameView.showView.delegate = self;
self.gameView.controlView.delegate = self;
self.gameView.msgToolBar.delegate = self;
/**
* 代理方實(shí)現(xiàn)具體登錄細(xì)節(jié)
*/
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password {
NSLog(@"username : %@, password : %@", username, password);
}
4. 代理屬性使用weak
- 首先
在我們的tableViewController中,控制器的view就是tableView,這就相當(dāng)于tableViewController強(qiáng)引用著tableView(代理對(duì)象)。 - 然后
當(dāng)我們?cè)O(shè)置delegate的時(shí)候,一般都是讓tableViewController成為代理,這個(gè)時(shí)候代理如果也使用strong,那么tableView的delegate又強(qiáng)引用著tableViewController,所以導(dǎo)致循環(huán)引用,因此代理得用weak! - 為什么不用assign
weak和assign是一種“非擁有關(guān)系”的指針,通過(guò)這兩種修飾符修飾的指針變量,都不會(huì)改變被引用對(duì)象的引用計(jì)數(shù)。但是在一個(gè)對(duì)象被釋放后,weak會(huì)自動(dòng)將指針指向nil,而assign則不會(huì)。在iOS中,向nil發(fā)送消息時(shí)不會(huì)導(dǎo)致崩潰的,所以assign就會(huì)導(dǎo)致野指針的錯(cuò)誤unrecognized selector sent to instance。
5.代理與block對(duì)比
- 在有多個(gè)消息傳遞時(shí),用delegate實(shí)現(xiàn)更合適,看起來(lái)也更清晰。block就不太好了,這個(gè)時(shí)候block反而不便于維護(hù),而且看起來(lái)非常臃腫,很別扭。
- 代理更加面相過(guò)程,block則更面向結(jié)果。
從設(shè)計(jì)模式的角度來(lái)說(shuō),代理更佳面向過(guò)程,而block更佳面向結(jié)果。例如我們使用NSXMLParserDelegate代理進(jìn)行XML解析,NSXMLParserDelegate中有很多代理方法,NSXMLParser會(huì)不間斷調(diào)用這些方法將一些轉(zhuǎn)換的參數(shù)傳遞出來(lái),這就是NSXMLParser解析流程,這些通過(guò)代理來(lái)展現(xiàn)比較合適。而例如一個(gè)網(wǎng)絡(luò)請(qǐng)求回來(lái),就通過(guò)success、failure代碼塊來(lái)展示就比較好。 - 從性能上來(lái)說(shuō),block的性能消耗要略大于delegate,因?yàn)閎lock會(huì)涉及到棧區(qū)向堆區(qū)拷貝等操作,時(shí)間和空間上的消耗都大于代理。而代理只是定義了一個(gè)方法列表,在遵守協(xié)議對(duì)象的objc_protocol_list中添加一個(gè)節(jié)點(diǎn),在運(yùn)行時(shí)向遵守協(xié)議的對(duì)象發(fā)送消息即可。
相關(guān)參考:
http://www.itdecent.cn/p/2113ffe54b30