iOS 使用位段為你的協議實現緩存功能

在設計接口的時候,委托是常用的交互方式,一般的,我們在使用協議時會寫出以下代碼。

if ([delegate respondsToSelector:@selector(someMothod:)]) {
        [delegate someMothod:(id)sender];
    }

一般情況下沒有問題,事實上,以上代碼可以滿足大部分的需求,但是假設你所實現的協議方法是一個類似網絡下載進度回調的功能,每隔很短的小段時間就需要回調一次呢?

你會發現,除了第一次檢測委托對象是否響應某個選擇子有意義外,之后的檢測都是多余的。如果委托對象本身沒變,那么不大可能會忽然不能響應某個選擇子。鑒于此,我們可以把委托對象能否響應某個協議方法這一信息緩存起來,已優化程序效率。

假設現在有一個進度回調的協議方法

- (void)networkDidUpdateProgressTo:(float)progerss;

以上方法由于需要監聽進度,需要頻繁地回調progress參數,如果能夠緩存委托對象能否響應的信息,我們就不必每次都去執行以下函數

if ([delegate respondsToSelector:@selector(someMothod:)])

將方法相應能力緩存起來的最佳途徑就是使用C語言的“位段”數據類型。

這里簡單介紹一下位段:
什么是位段呢? 位段是 C 語言特有的數據結構, 它允許我們定義一個由位組成的段, 并可為它賦以一個名字。
二進制位是數據的基本單位,它比字節還小,一個字節由 8 位組成, 而在某些計算機系統中則可能是 16 位。
事實上,如果需要標志一個信息,一位就足夠了,但是由于字節是存儲的最小單位,所以所有的變量至少要使用一個字節(比如BOOL值)。
如果我們想在一個很大的表中存儲很多標志, 那么 "被浪費" 的內存空間是很可觀的。幸運的是,在 C 語言中, 我們可以使用叫做位段的構造類型來定義一個結構體,從而定義某個字段所用的二進制位個數為某個特定的值。

struct data{                           //包含位段的結構體
    unsigned int fieldA : 8;    //位段fieldA,占8二進制位
    unsigned int fieldB : 4;    //位段fieldB,占4二進制位
    unsigned int fieldC : 2;    //位段fieldC,占2二進制位
    unsigned int fieldD : 1;    //位段fieldD,占1二進制位
}
//位段列表的形式為: 類型說明符 位域名:位域長度

以上結構體中,fieldA 位段將占用 8 個二進制位,fieldB 則為 4個,以此類推。于是,fieldA 可以表示 0 至 255 之間的值,而fieldD可以表示 0 或 1 這兩個值。

我們可以像 fieldD 這樣,把委托對象是否實現了協議中的相關方法這一信息緩存起來。如果創建的結構體中只有大小為 1 的位段,那么就能把很多 Boolean 值塞入一小塊數據里面了(原來存一個BOOL值的空間,現在能存8個),我們現在文件中聲明一個結構體。

struct {
    unsigned int delegateMothod1 : 1;
    unsigned int delegateMothod2 : 1;
    unsigned int delegateMothod3 : 1;
}  _delegateFlags;

然后重寫我們的delegate的setter方法:

-(void)setDelegate:(id<personalDelegate>)delegate
{
    _delegate=delegate;
    _delegateFlags.delegateMothod1=[delegate respondsToSelector:@selector(delegateMothod1:)];
    _delegateFlags.delegateMothod2=[delegate respondsToSelector:@selector(delegateMothod2:)];
    _delegateFlags.delegateMothod3=[delegate respondsToSelector:@selector(delegateMothod3:)];
}

現在委托對象如果能夠相應協議方法,位段就可以將其以一位的大小緩存起來,然后我們在之后調用委托對象的相關方法時,就不用檢測委托對象是否能響應給定的選擇子了,而是直接查詢結構體里的標志:

if (_delegateFlags._delegateFlags.delegateMothod1){
    [_delegate delegateMothod1:];
}

在相關方法要調用很多次的時候,值得進行這種優化,而是否需要優化,則應依照具體代碼來定。這需要分析代碼性能,并找出瓶頸,若發現執行速度需要改進,則可使用此技巧。如果要頻繁通過數據源協議從數據源中獲取多分相互獨立的數據,那么這項優化技術極有可能會提高程序效率。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,184評論 6 13
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,217評論 30 472
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,373評論 11 349
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,769評論 18 399
  • 早上經彭老師確認沒有下雨,我蹬上運動鞋,背上小包包,準備步行上班,到了樓下一看,明明淅淅瀝瀝下著雨,趕緊跑上樓...
    癟癟元子閱讀 262評論 1 3