iOS可變參數實現及原理剖析

你一定會時常見到有些方法的最後會有一個無關痛癢的 nil參數,可曾想過爲什麼要帶這個參數呢。

解答:因爲這裏參數的傳遞是可變參數的傳遞,拿[NSArray arrayWithObjects:]爲例子,我們進入他的接口文件去看會看到接口的實現是這樣的

 


+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;

最後的參數是一個宏定義,字面的意思是NS系列的‘需要以nil作爲終止符‘

這裏由於是可變參數,所以參數的個數並不確定,所有在系統進行遍歷該你傳進去的參數時會進行判斷是否讀取到nil的終止符。當讀到終止符nil時確定參數的個數停止進行遍歷

(這也就是爲什麼當數組中對象是nil值的時候,後面的值就加不進去的原因。所以數組的初始化儘量使用字面量形式,字面量可以導致錯誤展現出來。不至於不知道哪裏錯了)

由此,我們可以自己進行方法的設定時,也能實現可變參數的實現(Java的可變參數比objective-c要容易的多),實現如下

 


聲明

- (void)test:(NSString *)first,...NS_REQUIRES_NIL_TERMINATION;

實現

//可變參數

- (void)test:(NSString *)first,...{

//參數鏈表指針

va_list list;

//遍歷開始

va_start(list, first);

//知道讀取到下一個時nil時結束遞增

for (NSString *str = first; str != nil; str = va_arg(list, NSString*)) {

NSLog(@"%@",str);

}

//結束遍歷

va_end(list);

}

到這裏,你會想,既然va_list是一個鏈表指針,爲什麼沒有*呢。不錯,這裏確實是應該有一個 * 號但是,你再看,我們順藤摸瓜,進入 va_list的實現中去,他是這樣定義的

typedef __darwin_va_list va_list;

typedef void *  __darwin_va_list;   /* va_list */

沒錯,你會看到這裏他確實是一個指針,只不過給他重定義了而已。

在講他的實現原理的時候我們不得不牽扯C語言中可變參數的實現原理:C語言中的參數,編譯器會將多個參數從右向左挨個入棧,然後挨個出棧,所以只要我們知道參數列表中的第一個或者最後一個,就能夠挨個把他們取出來。

我們先講這裏的各個函數的作用,再去看C語言的實現。

1.va_start(ap, param)

這裏的函數作用是將參數列表的第一個參數的地址給我們之前定義的參數鏈表指針給賦值,用於系統進行遍歷取值。ap--我們之前定義的偏移指針 param--參數列表的第一個參數

2.va_arg(ap, type)

va_arg函數的作用是根據指針進行取值,取出值以後返回,並且指針偏移一位,ap---作用同上 type--參數的類型

3.va_end(ap)

參數列表遍歷完畢後我們需要將之前定義的指針偏移量給銷燬,以防出現意外。這裏屬於安全操作

說完這些方法的用處,那麼該講講C語言中的實現了


void fun(int a1, ...)

{

int *temp = &a;

temp++;

for (int i = 0; i < a; ++i)

{

//做你想要的操作

temp++;

}

}

 

C語言中的可變參數實現方法如上,我想就不用過多解釋了

作者:Jason_Msbaby
鏈接:https://www.jianshu.com/p/4e43d5478180
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

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