運行時編程block

      CallBack-回調,在各個編程語言中都是很重要的一個功能,比如彈窗一個子控件,在子控件中獲取到信息後需要返回數據給調用方,最主流的做法就是把調用方作爲參數傳到子控件中,然後當子控件拿到信息以後再把信息傳遞給之前進來的調用方。在iOS中,是通過一種叫delegate(代理)的方式來實現,通常在創建子控件的時候會看到一句:子控件.delegate = self, 意思是說,我就是這個子控件的代理,當子控件需要回調的時候,就直接調用其成員delegate(也就是我), 就可以把信息傳遞回去。

      然而在很多情況下這樣的代理會顯得很‘囉嗦’,比如我只是想簡單的彈出一個對話框(UIAlertView)然後知道用戶選擇的是Ok還是Cancel, 卻要在調用方做兩件事,首先是聲明這個對話框的協議(protocol)用以具備接收對話框回調的資格,然後再去實現回調方法,比如OnOk, OnCancel,等等,更麻煩的是,如果我在此有三個對話框的話,就要實現多個協議,做他們的代理。

       所以這裏可以用Block對其閉包,直接在上下文的地方聲明回調,不僅不用增加回調方法,而且很輕易的解決了多重回調的複雜局面。現在就拿UIAlertView舉一個例子:

       正常做法:調用方在召喚alertview的同時,將其代理指向自己:alertview.delegate = self; 然後在用戶點擊對話框上面的按鈕的時候,觸發其回調方法(如果它的代理存在的前提,如果沒有聲明指向的話不會被調用):

 

// Called when a button is clicked. The view will be automatically dismissed after this call returns

- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;

       這裏的優化思路是:

       修改UIAlertView這個類,增加一個block對象,然後讓其自己做自己的delegate, 調用方將block作爲參數傳進去以後,在自己的clickedButtonAtIndex方法中調用block即可。

       具體實現:

         1. 創建UIAlertView的類擴展,UIAlertView+Block;

         2. 聲明回調Block: 

typedefvoid (^UIAlertViewCompletionBlock) (UIAlertView *alertView,NSIntegerbuttonIndex);

         3. 增加接口,將block傳進來.

 

+ (instancetype)showWithTitle:(NSString *)title

                                 message:(NSString *)message

                                        style:(UIAlertViewStyle)style

                     cancelButtonTitle:(NSString *)cancelButtonTitle

                     otherButtonTitles:(NSArray *)otherButtonTitles

                                  tapBlock:(UIAlertViewCompletionBlock)tapBlock;

          4. 在設置tapBlock的時候,修改對象,新增成員變量,此處是核心:

 

 objc_setAssociatedObject(self,UIAlertViewTapBlockKey, tapBlock,OBJC_ASSOCIATION_COPY);

         *UIAlertViewTapBlockKey 不是字符串,是一個void*, 與tapBlock形成K-V唯一配對,向一個UIAlertView查key,就可以得到tapBlock作爲value返回。 這裏的setAssociatedObject是運行時編程中API,所以需要#import<objc/runtime.h>

         此時,tapBlock就已被植入到對象UIAlertView中,同時可以用key-value的方式獲取。

          5.將代理指向自己         

 

 self.delegate = (id<UIAlertViewDelegate>)self;

            6.實現代理方法- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex,在裏面調用植入的tabBlock. 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章