編碼篇-OC跨多層UI事件傳遞處理

前言

在 iOS 中,對象間的交互模式大概有這幾種:直接 property 傳值、delegate、KVO、block、protocol、多態、Target-Action 等等,本文介紹的是一種基于 UIResponder 對象交互方式,簡而言之,就是 通過在 UIResponder上掛一個 category,使得事件和參數可以沿著 responder chain 逐步傳遞。對于那種 subviews 特別多,事件又需要層層傳遞的層級視圖特別好用,但是,缺點也很明顯,必須依賴于 UIResponder 對象。

在項目開發中相信很多朋友都遇到過多層級view,事件拋出至VC處理的問題。 一般的處理方法都是使用 代理、回調、屬性傳值,可是多層級的View會讓整個流程非常痛苦和難于維護。

多層級View的UI事件處理有較好的方案,比如采用ReactiveCocoa、使用通知等等。可是ReactiveCocoa 的學習成本比較高,通知的話注冊通知,發送通知也是比較麻煩。

場景

一個VC的View上放了很多的子視圖,(中間有很多層)我們點擊了最上面的一個Button,需要把Button的tag傳到 VC中

Paste_Image.png

知識點( 此處不討論代理回調和通知。)

  • UIResponder類定義了一個對象接口用來響應和處理事件, 它是UIApplication, UIView以及UIView的子類(包括UIWindow)的父類, 這些類的實例對象被稱為響應對象或者響應者。

  • 然后UIResponder對象有一個重要的屬性叫做nextResponder, 下一個響應者,可以保證找到當前view的事件的接收者

  • 可以建立一個 UIResponder的類別,在類別中擴建一個方法,使所有的子類都可以調用.

  • 在需要處理的地方重寫 UIResponder的類別中的這個方法即可使整個傳遞終結掉。大大優化了整個事件處理過程。

由上至下的事件傳遞實現方法

#import "UIResponder+Router.h"
@implementation UIResponder (Router)
- (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo 
{
     if (self.nextResponder) { 
    [[self nextResponder] routerWithEventName:eventName userInfo:userInfo]; 
    }
}
@end

第一個參數是事件名稱, 第二個參數是需要傳遞的參數信息
看起來這樣一個方法會陷入死循環, 其實不然, 當self.nextResponder向上一直找到UIApplication都還不能響應事件的時候, 
系統就會自動丟棄這個事件

而當我控制器中重寫這個方法的時候, 相當于重寫父類方法的時候,
那么系統就會走子類的方法, 那么參數就直接傳遞給控制器了

*控制器中重寫父類方法*
- (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
  { 
      if ([eventName isEqualToString:YFTransferNameEvent]) { 
    NSString * name = userInfo[YFUserName]; 
    NSLog(@"用戶的姓名為:%@",name); 
  }    
}

*cell中Button的點擊事件*
- (void)buttonClickAction:(UIButton *)sender
 { 
      [sender routerWithEventName:YFTransferNameEvent 
    userInfo:@{ YFUserName:[self userName], }];
  }
Paste_Image.png

也就是說, button將事件處理傳遞給nextResponder, 也就是cell, cell沒有重寫父類方法, 繼續將事件傳遞給tableView, tableView也沒有重寫父類方法, 于是將事件處理傳遞給控制器的view,控制器的view也沒有重寫父類方法, 于是將事件處理傳遞給控制器, 控制器重寫了父類方法, 于是就走控制器重寫的方法, 進行事件處理, 事件就成功地從button傳到了控制器.

跨層處理事件后的回執

cell把事件傳遞給 VC后VC處理后怎么把結果返回給Cell使用呢,兩個方式:

  • 在上述的方法中把需要接受結果的對象指針傳過去,比如cell上一個按鈕要設置背景圖片,VC取完圖片在方法中獲取到這個按鈕的指針,VC通過這個指針通過直接操作內存的方式設置這個按鈕即可

  • 在類別的方法中定義 Block回調函數,cell發送事件,VC處理完后,通過Block把處理結果發送給 cell,供cell使用,這樣是最簡單的。

值得注意的是,這樣的事件傳遞處理方法,最常見的Bug就是當前試圖初始化后確實存在,但是沒有加載到父視圖上,才導致的方法無法觸發。

參考文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 在iOS開發中經常會涉及到觸摸事件。本想自己總結一下,但是遇到了這篇文章,感覺總結的已經很到位,特此轉載。作者:L...
    WQ_UESTC閱讀 6,133評論 4 26
  • 前言:按照時間順序,事件的生命周期是這樣的:事件的產生和傳遞(事件如何從父控件傳遞到子控件并尋找到最合適的view...
    貝勒老爺閱讀 1,015評論 1 9
  • 好奇觸摸事件是如何從屏幕轉移到APP內的?困惑于Cell怎么突然不能點擊了?糾結于如何實現這個奇葩響應需求?亦或是...
    Lotheve閱讀 58,011評論 51 603
  • 7、不使用IB是,下面這樣做有什么問題? 6、請說說Layer和View的關系,以及你是如何使用它們的。 1.首先...
    AlanGe閱讀 719評論 0 1
  • 史上最詳細的iOS之事件的傳遞和響應機制-原理篇http://www.lxweimin.com/p/2e074db7...
    Chris_C閱讀 1,440評論 0 8