Object-C中編寫省略參數(shù)的多參函數(shù)
Object-C中編寫省略參數(shù)的多參數(shù)函數(shù) 引語:
在Object-C中,我們會遇到很多像NSLog這樣的函數(shù),其中參數(shù)的個數(shù)不確定,由程序員自由控制,在初始化數(shù)組,字典等方面應(yīng)用廣泛,那么,這類的函數(shù)是如何實(shí)現(xiàn)的呢?我們怎么編寫我們自己的省略參數(shù)的函數(shù)呢?當(dāng)然,這不是唯一的多參函數(shù)的處理方法,你也可以通過一個字典或者數(shù)組傳遞參數(shù)。但C為我們提供的這樣的一種機(jī)制,無疑是最方便的。
一、了解幾個概念
- va_list
C語言中定義的一個指針,用于指向當(dāng)前的參數(shù)。
- va_start(ap,param)
這個宏是初始化參數(shù)列表,其中***個參數(shù)是va_list對象,第二個參數(shù)是參數(shù)列表的***個參數(shù)。
- va_arg(ap, type)
一個用于取出參數(shù)的宏,這個宏的***個參數(shù)是va_list對象,第二個參數(shù)是要取出的參數(shù)類型。
- va_end(ap)
這個宏用于關(guān)閉取參列表
二、多參函數(shù)的取參原理
在編寫我們自己的多參函數(shù)之前,明白函數(shù)的取參原理是十分重要的,首先,函數(shù)的參數(shù)是被放入我們內(nèi)存的棧段的,而且放入的順序是從后往前放入,比如如果一個函數(shù)參數(shù)如下:
- void func(int a,int b,int c,int d)
那么傳遞參數(shù)的時候參數(shù)d先入棧,接著是c、b、a。如此這樣,在取參的時候,根據(jù)堆棧的取值原則,則取值順序?yàn)閍、b、c、d。所以在原理上,只要我們知道***個參數(shù)的地址和每個參數(shù)的類型,我們就可以將參數(shù)都取出來。而上面介紹的幾個宏,就是幫助我們做這些的。
三、聲明與實(shí)現(xiàn)省略參數(shù)的多參函數(shù)
"..."這個符號就是我們用來實(shí)現(xiàn)省略參數(shù)函數(shù)的符號。例如我們模擬實(shí)現(xiàn)一個log函數(shù)如下: ? 1 2 3 4 5 6 7 8 9 10 -(void)myLog:(NSString *)str,...{//省略參數(shù)的寫法 va_list list;//創(chuàng)建一個列表指針對象 va_start(list, str);//進(jìn)行列表的初始化,str為省略前的***個參數(shù),及...之前的那個參數(shù) NSString * temStr = str; while (temStr!=nil) {//如果不是nil,則繼續(xù)取值 NSLog(@"%@",temStr); temStr = va_arg(list, NSString*);//返回取到的值,并且讓指針指向下一個參數(shù)的地址 } va_end(list);//關(guān)閉列表指針 }
注意,調(diào)用時,我們必須在參數(shù)的***加上nil這個判斷結(jié)束的條件: ? 1 [self myLog:@"312",@"321", nil];//必須有nil 四、一點(diǎn)補(bǔ)充
細(xì)心的你可能發(fā)現(xiàn)了,這里的nil是我們在調(diào)用函數(shù)時手動加上的,可是系統(tǒng)的許多函數(shù)在我們調(diào)用時,系統(tǒng)直接幫我們加上了參數(shù)結(jié)尾的那個nil,例如
- NSArray * array = [NSArray arrayWithObjects:(id), nil]
這是如何做到的呢?我們只需要在函數(shù)的聲明里加上一個宏,就可以實(shí)現(xiàn)這個功能,修改如下: ? 1 2 3 4 5 6 7 8 9 10 -(void)myLog:(NSString *)str,...NS_REQUIRES_NIL_TERMINATION{//這里加上一個宏 va_list list; va_start(list, str); NSString * temStr = str; while (temStr!=nil) { NSLog(@"%@",temStr); temStr = va_arg(list, NSString*); } va_end(list); }
顧名思義,這個宏的作用就是在結(jié)束位置加上我們需要的nil。