現在有一個需求, 如果一個自定義cell中有一個button, button的點擊事件要將自定義cell中的某個屬性值傳給控制器, 應該怎麼做?
當然你可以利用代理, 通知, 和block回調, 除此之外, 還有沒有其他辦法呢? 有! 那就是今天要說的路由響應鏈方法.
說到路由響應鏈, 其實跟路由器的路由半毛錢關系沒有. 關鍵在於響應鏈, 說到響應鏈, 就不得不說一下UIResponder
The UIResponder class defines an interface for objects that respond to and handle events. It is the superclass of UIApplication, UIView and its subclasses (which include UIWindow). Instances of these classes are sometimes referred to as responder objects or, simply, responders.
UIResponder類定義了一個對象接口用來響應和處理事件, 它是UIApplication, UIView以及UIView的子類(包括UIWindow)的父類, 這些類的實例對象被稱為響應對象或者響應者
然後UIResponder對象有一個重要的屬性叫做nextResponder, 下一個響應者. 現在回到我們的需求
響應者鏈當button向controller傳值的時候(紅色虛線箭頭方向), 這是逆傳, 大部分情況下我們都使用通知代理和block, 但是nextResponsder這個屬性讓我們可以直接獲取到控件的父類
首先,我為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], }]; }
也就是說, button將事件處理傳遞給nextResponder, 也就是cell, cell沒有重寫父類方法, 繼續將事件傳遞給tableView, tableView也沒有重寫父類方法, 於是將事件處理傳遞給控制器的view,控制器的view也沒有重寫父類方法, 於是將事件處理傳遞給控制器, 控制器重寫了父類方法, 於是就走控制器重寫的方法, 進行事件處理, 事件就成功地從button傳到了控制器.
響應者鏈傳遞實現效果如下圖, 我依次點擊每一個button,(注意:不是點擊cell),就會在控制器裡返回出結果, 並賦值給Label
實現效果具體的demo鏈接附在下面了, 有興趣的可以看一下, 非常簡單的
demo鏈接