iOS:在objective-c 使用可变参数
来源:互联网 发布:qq音乐数据库 api接口 编辑:程序博客网 时间:2024/06/05 03:29
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);- (instancetype)initWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION; // 注意区别
在c/c++中使用可变参数参考《C/C++ 使用可变参数 & 原理》,在objective-c中使用情况也差不多,一些宏定义说明如下:
----------------------------------------------------------------------------------------------------------------------------------
NS_FORMAT_FUNCTION(1,2)的意思:
// NSObjCRuntime.h#if !defined(NS_FORMAT_FUNCTION) #if (__GNUC__*10+__GNUC_MINOR__ >= 42) && (TARGET_OS_MAC || TARGET_OS_EMBEDDED)#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A))) #else#define NS_FORMAT_FUNCTION(F,A) #endif#endif
__attribute__,是GNU编译器的一个特性,这个宏是一个编译器指令,我们在代码中通过定义这个东西,可以inform编译器我们代码 的一些逻辑,从而在编译器避免一些错误,在运行期提高性能。__attribute__在很多代码中都有应用,非常实用。
__attribute__ format ,这个东西能告知编译器,我们的代码在处理printf,scanf这样变参数的函数的时候,哪个参数是format string,哪个参数是参数列表,这样可以避免代码中的一些问题,比如:
/* like printf() but to standard error only */extern void eprintf(const char *format, ...) __attribute__((format(printf, 1, 2))); /* 1=format 2=params *//* printf only if debugging is at the desired level */extern void dprintf(int dlevel, const char *format, ...) __attribute__((format(printf, 2, 3))); /* 2=format 3=params */从上面可以看出,我们定义了eprintf函数,第一个参数是Format String,第二个参数是对应Format String的参数列表,下面的dprintf也是一样,这样一来,编译器就能检测出下面这样的代码错误:
1 extern void eprintf(const char *format, ...)2 __attribute__((format(printf, 1, 2)));34 void foo()5 {6 eprintf("s=%s\n", 5); /* error on this line */78 eprintf("n=%d,%d,%d\n", 1, 2); /* error on this line */9 }$ cc -Wall -c test.ctest.c: In function `foo':test.c:6: warning: format argument is not a pointer (arg 2)test.c:8: warning: too few arguments for format其他一些__attribute__特性:__attribute__ const, 这个东西能告诉编译器,在给定参数的情况下,这个function始终返回同样的值。这样可以帮助程序提高性能,比如:
extern int square(int n) __attribute__((const));... for (i = 0; i < 100; i++ ) { total += square(5) + i; }如果我们在square函数中没有定义__attribute__ const的话,在下面的那个循环中,程序每次都要产生一个调用square函数的代码。但是这里指定了const之后,程序就知道,对于同一个输入参数 5,返回值都是一样的。这样程序就会执行一次square,然后cache这个函数的return value,这样下次循环开始,对square函数的调用就没有函数调用的逻辑了,直接返回上次的结果
----------------------------------------------------------------------------------------------------------------------------------
在objective-c中使用可变参数的例子:
- (void)foo:(NSString *)format, ...{ va_list args; va_start(args, format); NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; va_end(args); printf([str UTF8String]); [str release];} - (IBAction) doo: (UIButton*) sender{ //须留意不定参函数的调用格式,逗号分隔的序列,应该它们整体是作为函数的一个参数传入 [self foo : @"My name %@, %@", @"Unmi", @"Yes"];}
- (void)method:(NSString *)value,...{ //指向变参的指针 va_list list; //使用第一个参数来初使化list指针 va_start(list, value); while (YES) { //返回可变参数,va_arg第二个参数为可变参数类型,如果有多个可变参数,依次调用可获取各个参数 NSString *string = va_arg(list, NSString*); if (!string) { break; } NSLog(@"%@",string); } //结束可变参数的获取 va_end(list);}
函数调用:[self method:@"1",@"2",@"3",nil];像大多数变参函数一样,未尾一定要加上nil,因为这一组宏都没有提供对参数个数的检测,当然你可以会问为何NSLog的参数中我们都不用在末尾添加nil的参数呢,那是因为NSLog的第一个参数是一个格式化字符串,通过这个字条串就能获得后面的参数个数,所以如果你的函数还能有其它的参数能够显式的指出变参个数,当然你也可以书写(但在函数体中需要修改为按已知个数调用va_arg),仍然推荐以上的写法
@interface sqlHelper : NSObject { } -(int) executeInsertWithSql:(NSString *) statement, ...; @end .m文件 -(int) executeInsertWithSql:(NSString *) statement, ... { PLSqliteDatabase* dbPointer = [SqliteDataBase setUp]; argsArray = [[NSMutableArray alloc] init]; id arg; va_list argList; if(statement) { va_start(argList,statement); while (arg = va_arg(argList,id)) { [argsArray addObject:arg]; } va_end(argList); } BOOL bResult = [dbPointer executeUpdate:statement,[argsArray objectAtIndex:0],[argsArray objectAtIndex:1]]; return bResult; } // 在调用的时候要在参数结尾的时候加 nilsqlHelper *sqlCom = [[sqlHelper alloc] init]; [sqlCom executeInsertWithSql:@"INSERT INTO authorInfo(author,age) VALUES (?,?)",@"cheungching",@"25", nil];
-(void)vaMethod:(id)object1, ...{ va_list argList; id arg; if (object1) { va_start(argList, object1); while ((arg = va_arg(argList, id))) { NSLog(@"%@",arg); } va_end(argList); }}// 调用[self vaMethod:someObj,button,@"ss",nil];
注意第一个参数为object1,之后才是可变参数列表。
Disscussion:
--1.不定参数可以指定任何实际的类型,(id) 可真是任何类型了;
--2.Objective-C 的不定参数,即 ... 也必须放在函数的最后面,如还有其他参数时,foo 要写成:
- (void)fooState: (BOOL) enable withFormat: (NSString *)format, ... - (void)fooFormat: (NSString *)format, ... withState: (BOOL) enable // 错的
--3.在调用的时候要不要在参数结尾的时候加 nil,回想下 [NSMutableArray arrayWithObjects: 1, 2, 3, nil] 这个构造过程,最后一个 nil 能让 va_arg 取参数时碰到 nil 则断定为 NO,终止循环。为何像 NSLog 调用不需要最后一个 nil?Because -stringWithFormat: and NSLog can infer the number of arguments based on their format strings (the first argument). -arrayWithObjects: can't.
总结:在objective-c中使用可变参数格式为:(id)object1, ... 一般情况下object1为NSString类型,然后在方法内部使用va_start、va_arg等获取参数。至于调用的时候加不加nil,依赖于方法的实现,如果方法中以参数是否为nil作为结束条件(arg = va_arg(argList, id)为nil则va_end),则调用时必须加nil结尾。另外方法后可加一些宏定义(例如NS_FORMAT_FUNCTION(1,2))确定方法的一些格式,编译的时候对代码加以验证。
------------------------------------------------------------------------------------------------------------------
参考:
1.http://unmi.cc/obejctive-c-var-arguments/ 《Obejctive-C 中定义可变参函数》
2.http://mobile.51cto.com/iphone-280106.htm 《Objective-C可变参数函数定义》
3.http://www.cnblogs.com/super119/archive/2011/04/05/2005592.html 《Using GNU C __attribute__ 阅读笔记》
- iOS:在objective-c 使用可变参数
- iOS:在objective-c 使用可变参数
- iOS: Objective-C可变参数函数定义
- ios开发Objective-C可变参数函数
- Objective-C可变参数方法的定义和使用
- 详解Objective-C可变参数函数定义
- Objective-c 可变参数列表缺陷
- iOS va_list可变参数使用
- 在C/C++函数中使用可变参数
- 在C/C++函数中使用可变参数
- C 可变参数的使用
- C可变参数的使用
- C 参数可变宏使用
- objective-c 函数的可变参数 - argument lists
- objective-c 中可变参数: NS_FORMAT_FUNCTION(1,2);
- objective-c基础之可变参数列表va_list
- Objective-c学习笔记之可变长参数(...)
- Objective-C 可变数组
- linux 链接ln的使用 创建和删除符号连接(软、硬链接)
- ruby常用字符串处理函数
- 某人原创的排序
- uva 12086 - Potentiometers(树状数组)
- [SPOJ ORDERSET] Order statistic set [Splay]
- iOS:在objective-c 使用可变参数
- iOS Development Guideline
- 黑马程序员_多线程2
- POJ 3311 Hie with the Pie floyd+状压DP
- 找完工作该补充的东西
- Web安全扫描器
- 唯有不斷拼搏,才能遇見更美的風景
- Jsp分页显示示例
- 信号