以Responder Chain的方式傳遞View事件


概述

iOS開發(fā)中拴孤,View上的很多事件需要通過delegate回調委托到處理業(yè)務的地方坷澡。以回調到ViewController為例豆挽,當View樹的深度較大的時候育谬,終端節(jié)點View上的事件需要往ViewController傳遞時,我們需要沿著View的層級一級一級定義delegate帮哈,顯得比較麻煩膛檀。聯(lián)想到iOS中事件的響應鏈模型時,隱隱覺得可以借助這個鏈達到傳遞事件的目的娘侍。果然咖刃,前段時間讀到的一篇blog就探討了這個問題,鏈接如下:https://casatwy.com/responder_chain_communication.html

實踐

該blog里已經描述了實踐方式憾筏,這里為了使用時的便利嚎杨,嘗試做一些改進:

  1. 傳參時減少使用dictionary,而使用array的方式

如果一個事件在傳遞的過程中氧腰,需要在鏈上的某些結點收集/添加數據枫浙,這時用dictionary傳參的方式挺有必要的。
但是更多的調用場景是古拴,在某個View上發(fā)生事件時箩帚,把業(yè)務參數都帶上,期望直接傳到ViewController里的回調方法里黄痪。而使用dictionary作為參數紧帕,需要定義每個key值字符串,很麻煩且容易出錯满力。
我們可以直接按照ViewController里的方法參數順序焕参,把所有的參數裝到一個數組里,再調用出去油额。代碼如下:

UIResponder+Router.m:

- (void)routeEventWithName:(NSString *)eventName paramsList:(NSArray *)params {
        [[self nextResponder] routeEventWithName:eventName paramsList:params]; }

進一步叠纷,可以提供一個便捷方法,以可變參數列表的方式供調用潦嘶,收集好參數到數組里涩嚣,調用以上方法:

- (void)routeEventWithName:(NSString *)eventName wrappedValueParams:(NSValue *)firstWrappedParam, ... NS_REQUIRES_NIL_TERMINATION {
        NSMutableArray *argsArray = [[NSMutableArray alloc] init];
        va_list argList;
        if (firstWrappedParam) {
            [self addValueParam:firstWrappedParam toArray:argsArray];
            id arg;
            va_start(argList, firstWrappedParam);
            while (arg = va_arg(argList, id)) {
                [self addValueParam:arg toArray:argsArray];
            }
            va_end(argList);
        }
        [self routeEventWithName:eventName paramsList:argsArray];
    }
  1. 可變參數時的nil對象規(guī)避
    如上所述,個人覺得以可變參數的方式調用最為簡單自然掂僵。示例如下:
    [self routeEventWithName:@"EventSelectFundWithCode" wrappedValueParams:user.phone, user.name, nil];

這里有個問題航厚,user.phone參數如果為nil,則本次調用的參數經過va_list遍歷后都丟掉了锰蓬,這肯定違背了方法調用者的本意幔睬。
想了個解決方法來規(guī)避這個潛在的坑。我們規(guī)定芹扭,在調用時必須把參數都強制用NSValue包裝一下(即便是nil值也可以)麻顶,在va_list遍歷時再把wrap的實際對象解出來赦抖。這時,調用示例變成這樣了:

    [self routeEventWithName:@"EventSelectFundWithCode" wrappedValueParams:[NSValue valueWithNonretainedObject:user.phone], [NSValue valueWithNonretainedObject:user.name], nil];

解包的函數如下:

    -(void)addValueParam:(NSValue *)wrappedParam toArray:(NSMutableArray *)argsArray {
        if (![wrappedParam isKindOfClass:[NSValue class]] || [wrappedParam isKindOfClass:[NSNumber class]]) {
            DebugAssert(NO, @"Param should be wrapped by NSValue: %@", NSStringFromClass([wrappedParam class]));
        }
        id arg = [wrappedParam nonretainedObjectValue];
        arg = (arg != nil) ? arg : [NSNull null];
        [argsArray addObject:arg];
    }
  1. 以selector的方式處理業(yè)務
    在業(yè)務處理的節(jié)點辅肾,示例代碼如下:
    -(void)routeEventWithName:(NSString *)eventName paramsList:(NSArray *)params {
        NSDictionary *eventSelectorDict = @{ kEventSelectLimit : NSStringFromSelector(@selector(didSelectLimit:)), kEventSelectMinBuyAmount : NSStringFromSelector(@selector(didSelectMinBuyAmount:))};
        [self performSelector:NSSelectorFromString(eventSelectorDict[eventName]) withParams:params];
    }

這里跟blog里不同的是队萤,簡單地以selector字符串作為策略dictionary的value,然后在performSelector里再轉成selector矫钓。個人覺得最簡單要尔。
把performSelector的代碼也貼上:
NSObject+PerformSelector.m:

    -(id)performSelector:(SEL)aSelector withParams:(NSArray<id> *)params {
        NSInvocation *invocation = [self invocationWithSelector:aSelector];
        if (invocation == nil) {
            return nil;
        }
        NSInteger validArgumentsCount = MIN(invocation.methodSignature.numberOfArguments - 2, params.count);
        for (NSInteger i = 0; i < validArgumentsCount; i++) {
            id param = params[i];
            if ([param isKindOfClass:[NSNull class]]) {
                param = nil;
            }
            [invocation setArgument:&param atIndex:i+2];
        }
        [invocation invoke];
        
        id result = nil;
        if (invocation.methodSignature.methodReturnLength != 0) {
            [invocation getReturnValue:&result];
        }
        
        return result;
    }

總結

用響應鏈來傳遞事件的思路相當新穎和巧妙。用該模式確實可以省掉不少delegate的定義新娜。本文在實踐招式上的嘗試和優(yōu)化赵辕,權當作為一個參考。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末概龄,一起剝皮案震驚了整個濱河市匆帚,隨后出現的幾起案子,更是在濱河造成了極大的恐慌旁钧,老刑警劉巖吸重,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異歪今,居然都是意外死亡嚎幸,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門寄猩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫉晶,“玉大人,你說我怎么就攤上這事田篇√娣希” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵泊柬,是天一觀的道長椎镣。 經常有香客問我,道長兽赁,這世上最難降的妖魔是什么状答? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮刀崖,結果婚禮上惊科,老公的妹妹穿的比我還像新娘。我一直安慰自己亮钦,他們只是感情好馆截,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜂莉,像睡著了一般蜡娶。 火紅的嫁衣襯著肌膚如雪堪唐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天翎蹈,我揣著相機與錄音,去河邊找鬼男公。 笑死荤堪,一個胖子當著我的面吹牛,可吹牛的內容都是我干的枢赔。 我是一名探鬼主播澄阳,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼踏拜!你這毒婦竟也來了碎赢?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤速梗,失蹤者是張志新(化名)和其女友劉穎肮塞,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體姻锁,經...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡枕赵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了位隶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拷窜。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涧黄,靈堂內的尸體忽然破棺而出篮昧,到底是詐尸還是另有隱情,我是刑警寧澤笋妥,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布懊昨,位于F島的核電站,受9級特大地震影響春宣,放射性物質發(fā)生泄漏疚颊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一信认、第九天 我趴在偏房一處隱蔽的房頂上張望材义。 院中可真熱鬧,春花似錦嫁赏、人聲如沸其掂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽款熬。三九已至深寥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贤牛,已是汗流浹背惋鹅。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留殉簸,地道東北人闰集。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像般卑,于是被迫代替她去往敵國和親武鲁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內容

  • iOS網絡架構討論梳理整理中蝠检。沐鼠。。 其實如果沒有APIManager這一層是沒法使用delegate的叹谁,畢竟多個單...
    yhtang閱讀 5,172評論 1 23
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,128評論 29 470
  • 1. 單例寫法 單例模式確保某一個類只有一個實例饲梭,而且自行實例化并向整個系統(tǒng)提供這個實例。 一般情況下, 如果一個...
    sellse閱讀 1,002評論 0 1
  • 27焰檩、ViewController的didReceiveMemoryWarning是在什么時候調用的排拷?默認的操作是...
    煙雨平生花飛舞閱讀 566評論 0 1
  • 序言 目前形勢,參加到iOS隊伍的人是越來越多锅尘,甚至已經到供過于求了监氢。今年,找過工作人可能會更深刻地體會到今年的就...
    獨酌丿紅顏閱讀 2,361評論 18 60