《企业级ios应用开发实战》一3.6 可变参数

简介: 本节书摘来自华章出版社《企业级ios应用开发实战》一 书中的第3章,第3.6节,作者:杨宏焱,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.6 可变参数

我们知道,C和C++语言支持可变参数的函数,例如我们常用的NSLog和printf函数。Objective-C作为C语言的超集,当然毫无例外地也支持可变参数。迄今为止,我们至少用过了一种使用可变参数的方法,即NSString的stringWithFormat:方法。
C语言通过stdarg.h库支持可变参数,Objective-C 也不例外。在C语言中,如果你要使用可变参数,必须包含头文件stdarg.h,但在Cocoa中却不必,因为苹果已经在 NSObjC Runtime.h中包含了stdarg.h。
stdarg.h的定义如下:

typedef __void  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类型,其实就是一个void,即可以指向任何类型的指针。你可以把它看成是char,因为char*实际上也可以指向任何内存单元的地址。
然后是3个预定义宏,va_start、va_end和va_arg。可以看出stdarg.h完全是以“预定义宏”这种“古老”的方式来支持可变参数的。
接下来我们看一个例子,该方法使用了一个可变参数,并将这些可变参数进行了累加,然后返回一个NSNumber:

- (NSNumber ) addValues:(int) count, ... {
     va_list args;
     va_start(args, count);
     NSNumber value;
     double retval;
     for( int i = 0; i < count; i++ ) {
          value = va_arg(args, NSNumber );
          retval += [value doubleValue];
     }
     va_end(args);
     return [NSNumber numberWithDouble:retval]; 
}

代码说明:
第1行是方法定义,该定义应当加到头文件中。省略号...表明方法接收一系列数目不定的参数,在...前面至少需要指定一个任意类型的参数。有时我们必须知道参数的个数以防止出现无效的引用,但在某种情况下,参数个数是可以通过其他参数推断出来的(例如NSLog或printf函数可以通过计算%号的个数推断可变参数的个数),或者对于NSMutableArray来说,它总是以nil终止。
如果是最后一种方法,我们可以把方法重新定义为:

- (NSNumber ) addValues:(NSNumber ) firstNumber, ... 

这样,我们就可以用以下调用方式代替“addValues:3,num1,num2,num3”:

addValues:num1,num2,num3;

这样,我们就可以省略第1个表示可变参数个数的int参数。
第2行中的va_list是void *类型,因此它实际上是一个可变的对象数组。
第3行用args来存放可变参数列表,而count则表示函数最后一个参数(即第一个“固定参数”)。这将使编译器把args指向第1个参数后的位置(通过count地址加上count变量的长度)。
很奇怪吗?可变参数中第1个参数的位址为什么是“count地址+count的长度”?因为对于大多数C编译器,函数栈中参数的存放顺序是从右到左的,也就是说先放入可变参数的最后一个参数,再放可变参数的倒数第2个参数……,然后放可变参数的第1个参数,最后是固定参数count。而与此同时,栈的方向是向下的,即先入栈的数据位于高地址,后入栈的数据则位于栈的起始地址。这样,实际上最后放入的固定参数count的地址变成了栈的起始地址。而紧随count之后的地址则是可变参数的第1个参数地址,即“count地址+count的长度”,因此编译器要能找到第1个可变参数的地址,只要知道1个参数:count就够了,由count取得函数栈的起始地址,加上sizeof(count),得到第1个可变参数的地址。va_start的第1个参数args是一个输出参数,经过va_start调用之后,args将等于arg_start计算出来的第1个可变参数的地址。
第6行是一个for循环,因为我们无法通过 args 自身推断 args 的大小,因此必须显式地用count来指定args的大小。或者可以使用nil终止的列表来检索可变参数。
如果你使用nil终止的数组作为可变参数,则应该用下面一行来代替第6~7行:

while( value = va_arg( args, NSNumber  ) )

第 7 行将 args 中的下一个参数放入 value,并显式地转为 NSNumber*(如果不知道类型,可以用id)。
第10行表明,一旦使用完args列表,就关闭它 。
提示:如果你使用va_arg(args,double)(或者float等其他原始类型),那么当你试图传递一系列整数作为参数时(例如:addValues:4,4,3,2,1),可能会出现一些古怪的结果。而如果你显式地将这些参数说明为double(例如,double num1,double num2,double num3,double num4)则不会有什么问题。
这是因为,如果编译器看到一个方法有一个double参数但你却传递了一个整数给这个方法时,它会进行类型转换。但如果方法使用了可变参数,编译器无法知道参数所使用的类型,因此编译器只会简单地把参数作为整型处理。

相关文章
|
2月前
|
iOS开发 开发者
苹果iOS App Store上架操作流程详解:从开发者账号到应用发布
很多开发者在开发完iOS APP、进行内测后,下一步就面临上架App Store,不过也有很多同学对APP上架App Store的流程不太了解,下面我们来说一下iOS APP上架App Store的具体流程,如有未涉及到的部分,大家可以及时咨询,共同探讨。
|
2月前
|
开发者 iOS开发
iOS应用上架详细图文教程(上)
App Store作为苹果官方的应用商店,审核严格周期长一直让用户头疼不已,很多app都“死”在了审核这一关,那我们就要放弃iOS用户了吗?当然不是!本期我们从iOS app上架流程开始梳理,详细了解下iOS app上架的那些事。
|
4天前
|
存储 编解码 JSON
利用SwiftUI构建高效iOS天气应用
【4月更文挑战第21天】 在本文中,我们将深入探讨如何运用SwiftUI框架打造一个响应迅速且用户友好的iOS天气应用程序。我们将重点放在利用SwiftUI的声明式语法简化界面开发,并通过结合Core Location和Networking APIs实现实时天气数据的获取与展示。文章将详细阐述整个开发过程,包括API集成、数据模型设计、用户界面布局以及动态适配不同屏幕尺寸的策略。
|
1月前
|
安全 数据安全/隐私保护 虚拟化
iOS应用加固方案解析:ipa加固安全技术全面评测
iOS应用加固方案解析:ipa加固安全技术全面评测
37 3
|
1月前
|
运维 监控 安全
应用研发平台EMAS常见问题之sophix ios flutter热更新如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
77 0
|
1月前
|
Web App开发 前端开发 网络安全
前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
【2月更文挑战第21天】前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
58 1
前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
|
2月前
|
Linux Android开发 iOS开发
iOS 应用上架的步骤和工具简介
APP开发助手是一款能够辅助iOS APP上架到App Store的工具,它解决了iOS APP上架流程繁琐且耗时的问题,帮助跨平台APP开发者顺利将应用上架到苹果应用商店。最重要的是,即使没有配置Mac苹果机,也可以使用该工具完成一系列操作,包括iOS证书申请、创建iOS开发者证书和 iOS发布证书等各类证书。此外,在Windows、Linux或Mac系统中上传IPA到App Store也变得简单快捷,从而大大简化了iOS APP上架的流程。
|
2月前
|
移动开发 前端开发 安全
保护你的 iOS 应用,防止逆向破解
保护你的 iOS 应用,防止逆向破解
|
2月前
|
存储 安全 数据安全/隐私保护
iOS应用上架详细图文教程(下)
我们这边介绍一个简便的证书制作小方法。
|
2月前
|
安全 算法 数据安全/隐私保护
iOS 代码加固与保护方法详解 - 提升 iOS 应用安全性的关键步骤
iOS 代码加固与保护方法详解 - 提升 iOS 应用安全性的关键步骤