可变参数

简介

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

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