在iOS工程中憋他,通常我們的詳情頁面UI都是比較復雜的进陡,這就導致往往視圖層級較深,這種情況下萝衩,如果要將內(nèi)部的UIView識別到事件時回挽,拋出到VC來執(zhí)行具體處理,需要一層一層中轉(zhuǎn)猩谊,很麻煩千劈。
本文是介紹一種解決一層一層中轉(zhuǎn)直達VC的方式。
一牌捷、問題引出
如下是一個打車軟件的詳情截圖墙牌。我們分析頁面,打賞司機
按鈕的層級結(jié)構(gòu): UIButton -》ZLToolView -》ZLHeaderView -》UITableView -》ZLContentView -》VC.view -》 VC暗甥。
龍背嶺-東莞理工學院.jpeg
現(xiàn)在喜滨,如果我們點擊
打賞司機
,需要VC去執(zhí)行邏輯撤防。
1. 不管是使用代理或者block虽风,這個鏈路都很長。
這個事件首先是在ZLToolView
添加按鈕點擊監(jiān)聽寄月,然后需要中轉(zhuǎn)回調(diào)給ZLHeaderView
, 再回調(diào)給UITableView
的父視圖ZLContentView
, 最后再回調(diào)給VC辜膝。
2. 使用全局通知
如果使用通知的話,能做到跨層漾肮,但是缺點是通知更適合于全局的一對多場景厂抖,一個UI事件還是一對一的關(guān)系; 此外過多的通知也不利于維護。
二初橘、解決方案
上述問題我這邊思考的一個解決方案是通過響應者鏈來實現(xiàn)從內(nèi)層的View
事件跨層拋給VC
验游,理由如下:
- 響應者鏈在UIView添加到Superview上之后就存在,不用自己額外再建立責任鏈(響應者鏈其實是一個責任鏈設計模式)保檐。
- 通過響應鏈來傳遞可以使得鏈中任何關(guān)心這個事件的上級可攔截耕蝉。
- 實現(xiàn)的是一對一的響應。
具體的封裝代碼如下:
enum XLInnerViewEvent {
case refreshABC // 刷新ABC
case refreshDetail // 刷新詳情接口,如果有參數(shù)夜只,可以通過枚舉關(guān)聯(lián)值傳遞
}
protocol XLInnerEventResponsible: UIResponder {
func innerEventHandle(type: XLInnerViewEvent)
}
extension UIView {
// 一個沿著響應鏈向上傳遞事件的方法垒在,bubble=冒泡
func bubbleEvent(_ eventType: XLInnerViewEvent) {
var nextRespnder = self.next
while nextRespnder != nil {
if let savior = nextRespnder as? XLInnerEventResponsible {
savior.innerEventHandle(type: eventType)
nextRespnder = nil
}
nextRespnder = nextRespnder?.next
}
}
}
使用:
// 內(nèi)層view傳遞事件
@objc func reloadBtnAction() {
self.bubbleEvent(.refreshABC)
}
// VC或響應鏈中感興趣的類遵守協(xié)議XLInnerEventResponsible
extension VC: XLInnerEventResponsible {
func innerEventHandle(type: XLInnerViewEvent) {
switch type {
case .refreshABC:
print("refreshABC---")
case .refreshDetail:
print("refreshDetail---")
}
}
}