Objective-C语法之可变参数

可变参数的方法在Objective-C中不罕见,像Cocoa中的很多常见的方法都是可变参数的,如:

1 NSLog(NSString *format, ...)
2 + (id)arrayWithObjects:(id)firstObj, ...
3 + (id)dictionaryWithObjectsAndKeys:(id)firstObject , ...

那我们如何实现自己的变参方法呢,其实我们需要用到C语言中关于变参的一组宏:va_list,va_start,va_arg,va_end,以下示例是一个变参方法的实现:

main.m

 1 #import <Foundation/Foundation.h>
 2 #import "ChangeableParameterClass.h"
 3 int main(int argc, const char * argv[]) {
 4     @autoreleasepool {
 5         [ChangeableParameterClass method:@"测试可变参数"
 6                           withAuthorName:@"Kenmu"
 7                  withChangeableParameter:@"firstParameter", @"secondParameter", @"thirdParameter", @"fourthParameter", @"fifthParameter", nil];
 8     }
 9     return 0;
10 }

ChangeableParameterClass.h

 1 #import <Foundation/Foundation.h>
 2 @interface ChangeableParameterClass : NSObject
 3 /**
 4 *  测试可变参数
 5 *
 6 *  @param name           名称
 7 *  @param authorName     作者名称
 8 *  @param firstParameter 可变参数的第一个参数元素,“,...”表示可能存在后面的多个参数元素(可变参数必须是作为方法的最后一个参数,以“,...”方式结尾)
 9 */
10 + (void)method:(NSString *)name withAuthorName:(NSString *)authorName withChangeableParameter:(NSString *)firstParameter,...;
11 @end

ChangeableParameterClass.m

 1 #import "ChangeableParameterClass.h"
 2 @implementation ChangeableParameterClass
 3 + (void)method:(NSString *)name withAuthorName:(NSString *)authorName withChangeableParameter:(NSString *)firstParameter,... {
 4     NSLog(@"%@,作者:%@", name, authorName);
 5     
 6     va_list list; //指向可变参数的指针list
 7     va_start(list, firstParameter); //使用第一个参数来初使化指针list
 8     NSLog(@"strCurrent=%@", firstParameter); //strCurrent=firstParameter
 9     while (YES) {
10         NSString *strCurrent = va_arg(list, NSString *);
11         if (!strCurrent) {
12             break;
13         }
14         NSLog(@"strCurrent=%@", strCurrent); //strCurrent=secondParameter...
15     }
16     va_end(list); //结束可变参数的获取
17 }
18 @end

像大多数变参方法一样,未尾一定要加上nil,因为这一组宏都没有提供对参数个数的检测,当然你会问为何NSLog的参数中我们都不用在末尾添加nil的参数呢,那是因为NSLog的第一个参数是一个格式化字符串,通过这个字条串就能获得后面的参数个数,所以如果你的方法还能有其它的参数能够显式的指出变参个数,当然你也可以书写(但在方法体中需要修改为按已知个数调用va_arg),但是我仍然推荐以上的写法!