在設(shè)計接口的時候钉迷,委托是常用的交互方式至非,一般的,我們在使用協(xié)議時會寫出以下代碼糠聪。
if ([delegate respondsToSelector:@selector(someMothod:)]) {
[delegate someMothod:(id)sender];
}
一般情況下沒有問題荒椭,事實(shí)上,以上代碼可以滿足大部分的需求舰蟆,但是假設(shè)你所實(shí)現(xiàn)的協(xié)議方法是一個類似網(wǎng)絡(luò)下載進(jìn)度回調(diào)的功能趣惠,每隔很短的小段時間就需要回調(diào)一次呢?
你會發(fā)現(xiàn),除了第一次檢測委托對象是否響應(yīng)某個選擇子有意義外身害,之后的檢測都是多余的味悄。如果委托對象本身沒變,那么不大可能會忽然不能響應(yīng)某個選擇子题造。鑒于此傍菇,我們可以把委托對象能否響應(yīng)某個協(xié)議方法這一信息緩存起來,已優(yōu)化程序效率界赔。
假設(shè)現(xiàn)在有一個進(jìn)度回調(diào)的協(xié)議方法
- (void)networkDidUpdateProgressTo:(float)progerss;
以上方法由于需要監(jiān)聽進(jìn)度丢习,需要頻繁地回調(diào)progress參數(shù),如果能夠緩存委托對象能否響應(yīng)的信息淮悼,我們就不必每次都去執(zhí)行以下函數(shù)
if ([delegate respondsToSelector:@selector(someMothod:)])
將方法相應(yīng)能力緩存起來的最佳途徑就是使用C語言的“位段”數(shù)據(jù)類型咐低。
這里簡單介紹一下位段:
什么是位段呢? 位段是 C 語言特有的數(shù)據(jù)結(jié)構(gòu), 它允許我們定義一個由位組成的段, 并可為它賦以一個名字。
二進(jìn)制位是數(shù)據(jù)的基本單位袜腥,它比字節(jié)還小见擦,一個字節(jié)由 8 位組成, 而在某些計算機(jī)系統(tǒng)中則可能是 16 位钉汗。
事實(shí)上,如果需要標(biāo)志一個信息鲤屡,一位就足夠了损痰,但是由于字節(jié)是存儲的最小單位,所以所有的變量至少要使用一個字節(jié)(比如BOOL值)酒来。
如果我們想在一個很大的表中存儲很多標(biāo)志, 那么 "被浪費(fèi)" 的內(nèi)存空間是很可觀的卢未。幸運(yùn)的是,在 C 語言中, 我們可以使用叫做位段的構(gòu)造類型來定義一個結(jié)構(gòu)體堰汉,從而定義某個字段所用的二進(jìn)制位個數(shù)為某個特定的值辽社。
struct data{ //包含位段的結(jié)構(gòu)體
unsigned int fieldA : 8; //位段fieldA,占8二進(jìn)制位
unsigned int fieldB : 4; //位段fieldB翘鸭,占4二進(jìn)制位
unsigned int fieldC : 2; //位段fieldC滴铅,占2二進(jìn)制位
unsigned int fieldD : 1; //位段fieldD,占1二進(jìn)制位
}
//位段列表的形式為: 類型說明符 位域名:位域長度
以上結(jié)構(gòu)體中就乓,fieldA 位段將占用 8 個二進(jìn)制位汉匙,fieldB 則為 4個,以此類推生蚁。于是盹兢,fieldA 可以表示 0 至 255 之間的值,而fieldD可以表示 0 或 1 這兩個值守伸。
我們可以像 fieldD 這樣绎秒,把委托對象是否實(shí)現(xiàn)了協(xié)議中的相關(guān)方法這一信息緩存起來。如果創(chuàng)建的結(jié)構(gòu)體中只有大小為 1 的位段尼摹,那么就能把很多 Boolean 值塞入一小塊數(shù)據(jù)里面了(原來存一個BOOL值的空間见芹,現(xiàn)在能存8個),我們現(xiàn)在文件中聲明一個結(jié)構(gòu)體。
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:)];
}
現(xiàn)在委托對象如果能夠相應(yīng)協(xié)議方法蠢涝,位段就可以將其以一位的大小緩存起來玄呛,然后我們在之后調(diào)用委托對象的相關(guān)方法時,就不用檢測委托對象是否能響應(yīng)給定的選擇子了和二,而是直接查詢結(jié)構(gòu)體里的標(biāo)志:
if (_delegateFlags._delegateFlags.delegateMothod1){
[_delegate delegateMothod1:];
}
在相關(guān)方法要調(diào)用很多次的時候徘铝,值得進(jìn)行這種優(yōu)化,而是否需要優(yōu)化惯吕,則應(yīng)依照具體代碼來定惕它。這需要分析代碼性能,并找出瓶頸废登,若發(fā)現(xiàn)執(zhí)行速度需要改進(jìn)淹魄,則可使用此技巧。如果要頻繁通過數(shù)據(jù)源協(xié)議從數(shù)據(jù)源中獲取多分相互獨(dú)立的數(shù)據(jù)堡距,那么這項(xiàng)優(yōu)化技術(shù)極有可能會提高程序效率甲锡。