iOS可變參數(shù)實現(xiàn)及原理剖析
標簽(空格分隔): iOS可變參數(shù) iOS方法后面為什么有nil參數(shù)
你一定會時常見到有些方法的最后會有一個無關(guān)痛癢的 nil 參數(shù),可曾想過為什么要帶這個參數(shù)呢。
解答:因為這里參數(shù)的傳遞是可變參數(shù)的傳遞恐锦,拿[NSArray arrayWithObjects:]為例子癣诱,我們進入他的接口文件去看會看到接口的實現(xiàn)是這樣的
+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
最后的參數(shù)是一個宏定義虐杯,字面的意思是NS系列的‘需要以nil作為終止符‘
這里由于是可變參數(shù)六剥,所以參數(shù)的個數(shù)并不確定哥纫,所有在系統(tǒng)進行遍歷該你傳進去的參數(shù)時會進行判斷是否讀取到nil的終止符深纲。當(dāng)讀到終止符nil時確定參數(shù)的個數(shù)停止進行遍歷
(這也就是為什么當(dāng)數(shù)組中對象是nil值的時候劫灶,后面的值就加不進去的原因划址。所以數(shù)組的初始化盡量使用字面量形式扔嵌,字面量可以導(dǎo)致錯誤展現(xiàn)出來。不至于不知道哪里錯了)
由此夺颤,我們可以自己進行方法的設(shè)定時痢缎,也能實現(xiàn)可變參數(shù)的實現(xiàn)(Java的可變參數(shù)比objective-c要容易的多),實現(xiàn)如下
聲明
- (void)test:(NSString *)first,...NS_REQUIRES_NIL_TERMINATION;
實現(xiàn)
//可變參數(shù)
- (void)test:(NSString *)first,...{
//參數(shù)鏈表指針
va_list list;
//遍歷開始
va_start(list, first);
//知道讀取到下一個時nil時結(jié)束遞增
for (NSString *str = first; str != nil; str = va_arg(list, NSString*)) {
NSLog(@"%@",str);
}
//結(jié)束遍歷
va_end(list);
}
到這里世澜,你會想独旷,既然va_list是一個鏈表指針,為什么沒有*呢寥裂。不錯嵌洼,這里確實是應(yīng)該有一個 * 號但是,你再看封恰,我們順藤摸瓜麻养,進入 va_list的實現(xiàn)中去,他是這樣定義的
typedef __darwin_va_list va_list;
typedef void * __darwin_va_list; /* va_list */
沒錯,你會看到這里他確實是一個指針诺舔,只不過給他重定義了而已鳖昌。
在講他的實現(xiàn)原理的時候我們不得不牽扯C語言中可變參數(shù)的實現(xiàn)原理:C語言中的參數(shù),編譯器會將多個參數(shù)從右向左挨個入棧混萝,然后挨個出棧,所以只要我們知道參數(shù)列表中的第一個或者最后一個萍恕,就能夠挨個把他們?nèi)〕鰜怼?/p>
我們先講這里的各個函數(shù)的作用逸嘀,再去看C語言的實現(xiàn)。
1.va_start(ap, param)
這里的函數(shù)作用是將參數(shù)列表的第一個參數(shù)的地址給我們之前定義的參數(shù)鏈表指針給賦值允粤,用于系統(tǒng)進行遍歷取值崭倘。ap--我們之前定義的偏移指針 param--參數(shù)列表的第一個參數(shù)
2.va_arg(ap, type)
va_arg函數(shù)的作用是根據(jù)指針進行取值翼岁,取出值以后返回,并且指針偏移一位司光,ap---作用同上 type--參數(shù)的類型
3.va_end(ap)
參數(shù)列表遍歷完畢后我們需要將之前定義的指針偏移量給銷毀琅坡,以防出現(xiàn)意外。這里屬于安全操作
說完這些方法的用處残家,那么該講講C語言中的實現(xiàn)了
void fun(int a1, ...)
{
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
//做你想要的操作
temp++;
}
}
C語言中的可變參數(shù)實現(xiàn)方法如上榆俺,我想就不用過多解釋了。