也许这对你们大多数人来说显然很简单,但是您能否举例说明如何在 C 中创建类似的方法(在 Objective-C 中)和函数来创建像
NSString
的 stringWithFormat:
或 NSLog()
这样的函数
.
提醒一下:
[NSString stringWithFormat:@"example tekst %i %@ %.2f", 122, @"sth", 3.1415"];
NSLog(@"account ID %i email %@", accountID, email);
我想创建类似于
NSString
的方法stringWithFormat:
,NSURL - urlWithFormat
。
这些通常被称为“可变参数函数”(或方法)。
要创建它,只需使用 , ...
end方法声明,如 所示
- (void)logMessage:(NSString *)message, ...;
此时,您可能希望将其包装在类似
printf
的函数中,因为从头开始实现其中一个函数充其量只是尝试。
- (void)logMessage:(NSString *)format, ... {
va_list args;
va_start(args, format);
NSLogv(format, args);
va_end(args);
}
注意使用
NSLogv
而不是 NSLog
;考虑 NSLog(NSString *, ...);
与 NSLogv(NSString *, va_list);
,或者如果你想要一个字符串; initWithFormat:arguments:
于NSString *
。
另一方面,如果您不使用字符串,而是使用类似的东西
+ (NSArray *)arrayWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;
事情变得容易多了。
在这种情况下,不要使用
vprintf
式的函数,而是使用遍历 args
的循环,假设 id,然后像在任何循环中一样解析它们。
- (void)logMessage:(NSString *)format, ... {
va_list args;
va_start(args, format);
id arg = nil;
while ((arg = va_arg(args,id))) {
/// Do your thing with arg here
}
va_end(args);
}
当然,最后一个示例假设 va_args 列表以 nil 结尾。
注意:为了使这项工作成功,您可能必须包含
<stdarg.h>
;但如果没记错的话,它会与 NSLogv 一起包含在内,这意味着它是通过“Foundation.h”下降的,因此也是“AppKit.h”和“Cocoa.h”以及其他一些;所以这应该是开箱即用的。
- (void)methodWithFormat:(NSString*)format, ... {
va_list args;
va_start(args,format);
//loop, get every next arg by calling va_arg(args,<type>)
// e.g. NSString *arg=va_arg(args,NSString*) or int arg=(args,int)
va_end(args);
}
如果要将变量参数传递给 stringWithFormat:,请使用类似:
NSString *s=[[[NSString alloc] initWithFormat:format arguments:args] autorelease];
这里需要提到的是,这里的第一个 NSString 参数是作为 format 来的,另一个是在变量参数中传递的。正确的?因此,在进入 for 循环之前,您需要处理一个参数。
- (NSString *) append:(NSString *)list, ...
{
NSMutableString * res = [NSMutableString string];
[res appendString:list];
va_list args;
va_start(args, list);
id arg = nil;
while(( arg = va_arg(args, id))){
[res appendString:arg];
}
va_end(args);
return res;
}
- (void) test_va_arg
{
NSString * t = [self append:@"a", @"b", @"c", nil];
STAssertEqualObjects(@"abc", t, @"");
}
#import <Foundation/Foundation.h>
#define GS_MAX_OBJECTS_FROM_STACK 128
#define GS_USEIDLIST(firstObject, code...) ({\
va_list __ap; \
unsigned int __max = GS_MAX_OBJECTS_FROM_STACK; \
unsigned int __count = 0; \
id __buf[__max]; \
id *__objects = __buf; \
id __obj = firstObject; \
va_start(__ap, firstObject); \
while (__obj != nil && __count < __max) \
{ \
__objects[__count] = __obj; \
__obj = va_arg(__ap, id); \
if (++__count == __max) \
{ \
while (__obj != nil) \
{ \
__count++; \
__obj = va_arg(__ap, id); \
} \
} \
} \
va_end(__ap); \
if (__count > __max) \
{ \
unsigned int __tmp; \
__objects = (id*)NSZoneMalloc(NSDefaultMallocZone(),__count*sizeof(id)); \
va_start(__ap, firstObject); \
__objects[0] = firstObject; \
for (__tmp = 1; __tmp < __count; __tmp++) \
{ \
__objects[__tmp] = va_arg(__ap, id); \
} \
va_end(__ap); \
} \
code; \
if (__objects != __buf) NSZoneFree (NSDefaultMallocZone(),__objects); \
})
@interface MyObject : NSObject
- (void)printWithObjects:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
@end
@implementation MyObject
- (void)printWithObjects:(id)firstObject, ... {
GS_USEIDLIST(firstObject, {
for (unsigned int i = 0; i < __count; i++) {
NSLog(@"%@", __objects[i]);
}
});
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[[MyObject new] printWithObjects:@"1", @"2", @"3", nil];
}
return 0;
}