可变参数

简介

一个可变参数的函数是指该函数拥有不定的参数,参数个数可能为0个,1个或者多个。
在OC中常见的系统可变参数函数有下面两个

- (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 
NS_EXTENSION_UNAVAILABLE_IOS("Use UIAlertController instead.");
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NS_NO_TAIL_CALL;

NS_REQUIRES_NIL_TERMINATION是一个宏定义,用于编译时非nil结尾的检查

使用可变参数需要注意的点

  • 一个方法最多只能有一个可变参数
  • 可变参数一定要放在方法的末尾
  • 在可变参数里,多个参数均以逗号隔开
  • 一般来说调用可变参数一般会以nil结尾

对于最后一点,在调用NSLog函数的时候,经常会这么写NSLog(@"set : %@", set);然而并没有在最后添加nil表示可变参数的结束,这是因为根据前面的format表达式,可以得知预期的参数个数,所以不用以nil来表示结束。
例如

//预期一个参数,所以@"2"这个参数不会被用到,输出test : 1
NSLog(@"test : %@", @"1", @"2");
NSLog(@"test : %@");//运行报错EXC_BAD_ACCESS
NSLog(@"test : %f");//test : 0.000000
NSLog(@"test : %d");//test : 8

创建自己的可变参数方法

在方法末尾添加NS_REQUIRES_NIL_TERMINATION有一个好处就是在调用该方法的时候,如果可变参数没有以nil结尾,则系统会出现一个警告Missing sentinel in method dispatch;如果没有添加这个宏,就不会有这个警告,所以推荐在方法末尾添加这个宏

- (NSString *)books:(NSString *)book, ... NS_REQUIRES_NIL_TERMINATION
{
    NSMutableString *str = [NSMutableString new];
    
    if (book) {
        [str appendString:book];
        
        NSString *value;
        
        //该指针变量指向可变参数列表
        va_list arg_list;
        //让arg_list指向第一个可变参数列表的第一个参数,开始提取可变参数列表的参数
        va_start(arg_list, book);
        //va_arg用于提取arg_list指针当前指向的参数,并将指针移动到下一个参数
        //如果当前获取到的参数不为nil,则进行相关操作
        while ((value = va_arg(arg_list, NSString *))) {
            [str appendFormat:@" + %@", value];
        }
        //释放arg_list指针,提取结束
        va_end(arg_list);
    }
    
    return [str copy];
}

NSLog(@"str = %@", [self books:nil]);//str = 
NSLog(@"str = %@", [self books:@"Objc", nil]);//str = Objc
NSLog(@"str = %@", [self books:@"Objc", @"Java", nil]);//str = Objc + Java
- (NSInteger)sum:(NSInteger)num, ... NS_REQUIRES_NIL_TERMINATION
{
    NSInteger result = num;
    NSInteger value = 0;
    
    va_list arg_list;
    
     //如果不添加这句,在调用[self sum:nil]后打印的是sum = 140393006011167,不符合预期
    if (arg_list->gp_offset == arg_list->fp_offset) {
        return 0;
    }
    
    va_start(arg_list, num);
    while ((value = va_arg(arg_list, NSInteger))) {
        result += value;
    }
    
    va_end(arg_list);
    
    return result;
}
NSLog(@"sum = %ld", [self sum:nil]);//sum = 0
NSLog(@"sum = %ld", [self sum:1, 2, nil]);//sum = 3
NSLog(@"sum = %ld", [self sum:1, 3, 2, 4, nil]);//sum = 10

如果在方法中指定可变参数的个数,那么可变参数可以不以nil结尾,不过可能会出现指定个数和参数个数不一致的问题,所以不推荐这个写法

- (NSString *)count:(NSInteger)count books:(NSString *)book, ...
{
    NSMutableString *str = [NSMutableString new];
    
    if (book) {
        [str appendString:book];
        
        NSString *value;
        
        va_list arg_list;
        va_start(arg_list, book);
        
        for (NSInteger i = 1; i < count; i++) {
            value = va_arg(arg_list, NSString *);
            [str appendFormat:@" + %@", value];
        }
        
        va_end(arg_list);
    }
    
    
    
    return [str copy];
}
NSLog(@"total = %@", [self count:0 books:nil]);//total = 
NSLog(@"total = %@", [self count:1 books:@"Objc"]);//total = Objc
NSLog(@"total = %@", [self count:2 books:@"Objc", @"Java"]);//total = Objc + Java
- (NSInteger)sumWithCount:(NSInteger)count values:(NSInteger)num, ...
{
    NSInteger result = num;
    NSInteger value;
    
    va_list arg_list;
    
    va_start(arg_list, num);
    
    for (NSInteger i = 1; i < count; i++) {
        value = va_arg(arg_list, NSInteger);
        result += value;
    }
    
    va_end(arg_list);
    
    return result;
}
NSLog(@"sum1 = %ld", [self sumWithCount:0 values:nil]);//sum1 = 0
NSLog(@"sum1 = %ld", [self sumWithCount:2 values:1, 2]);//sum1 = 3
NSLog(@"sum1 = %ld", [self sumWithCount:4 values:1, 3, 2, 4]);//sum1 = 10

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、可变参数是什么 想定义一个方法,但是不知道以后要用的时候想传几个参数进去,最经典的例子就是UIAlertVie...
    小道萧兮阅读 2,190评论 1 8
  • 我们在C语言编程中会遇到一些参数个数可变的函数,例如printf() 这个函数,它的定义是这样的: int pri...
    Mr_Me阅读 762评论 0 2
  • 简介 一个可变参数函数是指一个函数拥有不定的参数,即为一个函数可接收多个参数。有时我们会遇到一些算术问题需要用到,...
    lancely阅读 14,871评论 2 19
  • 可变参数的函数在Objective-C中不罕见,像Cocoa中的很多常见的函数都是可变参数的,如: NSLog(N...
    哈哈哈我的简书账号阅读 979评论 0 1
  • 近年来,关于加班的争论从来没有消停过。其中被深扒最多的当属华为公司了,在加班问题上被裸体鞭打了无数次。任正非...
    Tearsweet阅读 336评论 0 0