你必定會時常見到有些方法的最後會有一個無關痛癢的 nil 參數,可曾想過爲何要帶這個參數呢。
解答:由於這裏參數的傳遞是可變參數的傳遞,拿[NSArray arrayWithObjects:]爲例子,咱們進入他的接口文件去看會看到接口的實現是這樣的objective-c
+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
最後的參數是一個宏定義,字面的意思是NS系列的‘須要以nil做爲終止符‘
這裏因爲是可變參數,因此參數的個數並不肯定,全部在系統進行遍歷該你傳進去的參數時會進行判斷是否讀取到nil的終止符。當讀到終止符nil時肯定參數的個數中止進行遍歷
由此,咱們能夠本身進行方法的設定時,也能實現可變參數的實現(Java的可變參數比objective-c要容易的多),實現以下安全
//可變參數 - (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語言的實現。spa
這裏的函數做用是將參數列表的第一個參數的地址給咱們以前定義的參數鏈表指針給賦值,用於系統進行遍歷取值。ap--咱們以前定義的偏移指針 param--參數列表的第一個參數指針
va_arg函數的做用是根據指針進行取值,取出值之後返回,而且指針偏移一位,ap---做用同上 type--參數的類型code
參數列表遍歷完畢後咱們須要將以前定義的指針偏移量給銷燬,以防出現意外。這裏屬於安全操做接口
說完這些方法的用處,那麼該講講C語言中的實現了get
void fun(int a1, ...) { int *temp = &a; for (int i = 0; i < a; ++i) { //作你想要的操做 temp++; } }
C語言中的可變參數實現方法如上,我想就不用過多解釋了。編譯器