美文网首页
可变参数

可变参数

作者: c048e8b8e3d7 | 来源:发表于2016-12-30 17:32 被阅读166次

    简介

    一个可变参数的函数是指该函数拥有不定的参数,参数个数可能为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
    
    

    相关文章

      网友评论

          本文标题:可变参数

          本文链接:https://www.haomeiwen.com/subject/zibmvttx.html