iOS 回調方法使用總結

     在iOS OC編程中,很多場景都會使用回調,尤其和C、C++代碼的數據交互上,使用回調,會很方便。那麼在OC中都可以使用那些回調方法呢?總結了以下6種:

一、Block方式
Block是OBJC提供的一種運行時方法機制,由c函數實現,它提供了一種運行時的臨時回調機制。
Block對象的聲明:
聲明一個參數爲int,返回值爲int,帶2個int參數的Block對象block。
int (^block)(int,int);

通過typedef簡化

typedef int (^block)(int,int);
block bl = ^(int a,int b){
return a+b;
}

//回調函數定義:

- (int)handleBlockCallbackFunc: (block)callback
  {
      return callback(10,12);
  }

回調函數使用:

int ret = [self handleBlockCallbackFunc:
                 ^(int param,__unused int b) {
                   NSLog(@"Block Msg: %d", param);
                   return param*2;
                 }];

警告:

block對象使用的變量、參數在運行時被綁定,因此可以直接使用棧空間建立的變量,無需參數傳入。但block對象的創建依然有生命週期限制,因此傳入異步調用的block對象時,如果是棧空間創建的block,必須
使用Block_copy()將block拷出備份,然後使用Block_release()將block釋放。
對於在棧空間聲明的變量,綁定到block時被標記爲const。只能讀取不能寫入。如果需要寫入,需要用__block對變量進行標記。此時block使用的是從棧拷貝到堆中的對象。當出block時,如果棧可用則將堆中對象自動拷貝回棧。
優點:
最輕量級的回調機制
編譯器類型檢查
如函數指針一樣,靈活定義回調函數
缺點:
執行效率。(影響程度不清楚)
容易導致代碼邏輯集中
二、函數指針方式
C語言回調機制。
優點:
輕量級的回調機制
只約定返回值和參數,而非函數名。無參數、返回值限制,使用靈活
編譯器提供類型檢查。(錯誤時產生警告)
缺點:
與OBJC的消息機制不兼容。因爲消息並非C語言中那樣,函數名對應函數指針。即只能對C函數進行回調
傳入不符合約定的函數指針時,產生副作用繼續運行,而非報錯
 
三、respondsToSelector和performSelector
利用RunTime特性進行回調
優點:
- 與OBJC代碼兼容性好
- 具有延遲執行等特性
- 輕量級的回調機制
 
缺點:
回調產生的返回值只能爲id類型,基本數據類型會產生錯誤
參數最多隻能傳入兩個。但可以通過建立包含多個參數的參數類進行迴避。同時返回值限制也可通過此方式解決,即建立一個輸入類和一個輸出類。NSInvocation也提供了多參數的解決方法
如果以
[target performSelector: @selector(callback)];

 方式建立回調,則需要對類的回調消息名建立約定,且回調消息名具有獨佔性,即一個類中只能以此消息名進行回調。

如果通過外部傳入SEL建立回調
[target performSelector: sel];

或是外部傳入字符串建立回調

[target performSelector:NSSelectorFromString(@"callback")];

       使用自動引數編譯器特徵(ARC)會產生警告“performSelector may cause a leak because its selector is unknown”

使用此種方式建立回調,當傳入一個不符合約定的消息時,會產生副作用繼續運行,而非報錯。比如約定消息有2個參數,但傳入消息只有1個參數,則按照參數約定順序屏蔽掉最後傳入的參數。或是傳入消息具有3個參數,則多餘的參數值未初始化。
 
四、objc_msgSend
需要導入#import
id objc_msgSend(id theReceiver, SEL theSelector, ...)
優點:
輕量級的回調機制
無傳入參數限制
相比performSelector,使用自動引數特徵時,不產生警告
同系列的方法支持double、struct等類型的返回值,但仍然不支持int型返回值(可使用NSNumber包裝以迴避)
缺點:
傳入不符合約定的消息時,產生副作用繼續運行,而非報錯
 
 
五、NSNotificationCenter方式
NSNotificationCenter是OBJC提供的消息機制。它有些類似於觀察者模式,通過關注感興趣的消息,建立回調。NSNotificationCenter提供了一種低耦合的對象通訊機制,特別適合無指定對象的一對多回調。
(1).獲取消息中心實例(系統已創建,單件模式)
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
(2).發送消息。(事件發生時調用)
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc postNotificationName: NOTIFY_MSG_UC_COMMON_PLAYER_PLAY   // 消息名(字符串)
                      object:self                                // 消息源
                    userInfo:nil];                               // 用戶字典(傳遞更多自定義參數)

 

(3).註冊消息
  [nc addObserver: self                              // 觀察者
           selector: @selector(handleNotify_Play:)     // 回調
               name: NOTIFY_MSG_UC_COMMON_PLAYER_PLAY  // 監聽消息
             object: nil];                             // 消息源

(4).註銷消息

[nc removeObserver: self];

(5).回調定義

- (void) handleNotify_Play:(NSNotification *)note;
      只有一個參數
     NSNotification*
     –name      // 消息名
    –object    // 消息源
    –userInfo  // 用戶字典

優點:

1)、回調對象間耦合度低。相互之間可不必知道對方存在;
2)、通過消息傳遞的信息無限制;
3)、觀察者可選擇特定消息、特定對象,或者特定對象的特定消息進行觀察。
缺點:
        缺乏時序性。當事件發生時,回調執行的先後次序不確定。也不能等待回調完成執行後續操作。解決:1)使用傳統回調機制。2)多線程時,可使用NSCondition同步線程。3)使用更多的消息。(過多使用可能導致混亂)
 
六、IMP方式
        類似於OBJC提供的函數指針,它通過methodForSelector方法查詢傳入的Selector,以獲得函數的入口地址,一般不用RunTime特性幾乎用不到!
  id (*IMP)(id, SEL, ...)
相比普通C語言的函數指針,其定義多了id,SEL這兩個強制參數約定
優點:
輕量級的回調機制
傳入不符合約定的消息時,報錯
無傳入參數限制。返回值可通過強轉獲得,無類型限制
typedef int (*CBFUNC)(id, SEL, int, int, int); // 定義函數指針類型
int ret = ((CBFUNC)callback)(self, sel, param1, param2, param3); // 強制轉換

這裏的id和SEL只是OBJC系統約定的佔位,自定義回調時無實際意義

缺點:
不能提供如同協議和函數指針的編譯期類型檢查。
 

IOS回調方法應用場景總結:

(1).單純的回調,且沒有複用的必要,也無IOS版本限制,可採用block

(2).單純的回調,有複用要求,可使用performSelector、objc_msgSend,或是IMP的回調機制

(3).使用自動引數的情況下,儘量不使用performSelector回調傳入的@Selector,防止警告

(4).對象間有較多的互操作,對象有複用的必要,可採用協議

(5).無指定對象的一對多回調採用NSNotificationCenter

(6).有延遲調用等特殊應用的,可以使用performSelector

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