iOS代理模式

概述

代理模式是一種消息傳遞方式,一個(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容