前言
在OC和Swift都是允许使用可变参数方法的,虽然可变参数方法在很大程度上违反了编码规范,但是在一些特定场景却又很好用。例如我们在OC中常用的方法NSLog以及Swift中使用的print。
在Swift中定义可变参数方法
class VariableArgumentsFunction: NSObject {
func variableArg1(args: Any...) -> Void {
print(args)
}
func variableArg2(first: Any, _ args: Any...) -> Void {
print(first)
print(args)
}
}
在Swift中定义可变参数方法很简单,参数的类型后面加上... 就可以了。在使用时,调用方传值的可变参数会以数据的形式存放在args中。
在OC中定义可变参数方法
+ (void)variableArg:(id)arg,... NS_REQUIRES_NIL_TERMINATION {
va_list args;
va_start(args, arg);
NSLog(@"%@", arg);
while (1) {
id arg = va_arg(args, id);
if (arg == nil) {
break;
}
NSLog(@"%@", arg);
}
va_end(args);
}
+ (void)variableArg1:(id)arg1 arg2:(id)arg2, ... NS_REQUIRES_NIL_TERMINATION {
va_list args;
va_start(args, arg2);
NSLog(@"%@", arg1);
NSLog(@"%@", arg2);
while (1) {
id arg = va_arg(args, id);
if (arg == nil) {
break;
}
NSLog(@"%@", arg);
}
va_end(args);
}
在OC中定义可变参数方法会略显复杂。
方法声明时在参数后面加 , ... ,最好是为方法加上NS_REQUIRES_NIL_TERMINATION进行修饰,这个宏定义是提示调用者这个方法的参数需要以nil结尾。
方法体中需要使用va_list来获取可变参数列表,关于va_list会在后面的内容进行描述。
调用方法时需要注意:
- 可变参数的类型都需要与
, ...前面的这个参数的类型一致。 - 如果不以
nil结尾,在va_arg时会报错。
关于va_list
VA_LIST 是在C语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>,用于获取不确定个数的参数。
在OC中va_list的定义如下:
typedef __darwin_va_list va_list;
其它几个相关函数定义如下:
#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
本篇文章不对这些函数进行深入的挖掘,只简单的解释这些函数的用法。
-
va_list用于承载可变参数列表。在方法体中使用va_list args;来让args变量接收可变参数列表 -
va_start获取可变参数列表的第一个参数的地址(ap为va_list,param为方法声明中可变参数左边的那一个参数。也就是上面第一个方法中定义的arg,第二个方法中的arg2) -
va_arg获取可变参数的当前参数,返回指定类型并将指针指向下一参数(type为参数的数据类型) -
va_end清空va_list可变参数列表
在方法体中有几点需要注意:
-
va_list中不包含可变参数左边的那一个(上面第一个方法中定义的arg,第二个方法中的arg2),所以在使用的时候需要注意。 - 参数的类型需要在方法体中自行控制,编译器不会对参数的类型进行严格检查,所以使用的时候需要考虑做类型校验,防止报错。
- 使用完参数之后,记得调用
va_end,防止出现灵异情况。










网友评论