可變參數、不定參數是什麼
我這裏所說的可變參數或不定參數是指, 方法中的某個形式參數可以接收多個參數(不確定個數的參數)。就比如, 下面的一些系統的方法:
[NSArray arrayWithObjects:@"first", @"second", @"third"];
[[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@ otherButtonTitles:@"first", @"second", @"third", nil];
// Method Reference
+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
- (instancetype)initWithTitle:(nullable NSString *)title message:(nullable NSString *)message delegate:(nullable id /*<UIAlertViewDelegate>*/)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION
以上這兩個方法都是系統的方法, NSArray
方法中的firstObj
和UIAlertView
方法中的otherButtonTitles
都是可變參數。
實現可變參數的方法
自定義一個方法printMessages:
實現可變參數:
- (void)printMessages:(nullable NSString *)messages, ... NS_REQUIRES_NIL_TERMINATION {
if (messages) {
// 取出第一個參數(這是固定參數)
NSLog(@"固定參數: %@", messages);
// 定義一個參數列表指針
va_list args;
// 存放所取參數的指針
NSString *arg;
// 初始化va_list變量
va_start(args, messages);
// 取出va_list中存儲的可變參數(不包含固定參數), 取出後args指向參數列表中的下一個參數
while ((arg = va_arg(args, NSString *))) {
NSLog(@"可變參數: %@", arg);
}
// 清空參數列表,並將va_list的指針置爲NULL
va_end(args);
}
}
調用方法:
[self printMessages:@"first", @"second", @"third", nil];
打印結果:
固定參數: first
可變參數: second
可變參數: third
實現可變參數的原理
在上面的代碼中, 讀取可變參數的過程其實就是在堆棧中,使用指針, 遍歷堆棧段中的參數列表, 從低地址到高地址一個一個地把參數內容讀出來的過程。
歸根到底還是通過 va_list
、va_start
、va_arg
、va_end
這四個宏的功能來實現的。它們就是C語言中用來解決變參問題的一組宏。
它們的具體作用如下:
va_list
: 用於獲取不確定個數的參數, 保存宏 va_start
、va_arg
和 va_end
所需信息的一種類型。爲了訪問可變參數列表中的參數,必須聲明一個 va_list
類型的指針。
va_start
: 初始化 va_list
,獲取可變參數列表的第一個參數的地址。初始化結果供宏va_arg
和va_end
使用。
va_arg
: 獲取可變參數的當前參數,返回指定類型並將指針指向下一參數
va_end
: 清空va_list
可變參數列表,並該指針置爲NULL