2009-07-30 91 views
7

假设我有签名的方法:什么是正确的方式来包装[NSString stringWithFormat:]?

+ (NSString *) myFormattedString:(NSString *)format, ...; 

而且我希望它前面加上我的选择(例如@“富”)的字符串。我想最好的方法是使用[myString initWithFormat:arguments:],但是你将如何实现这个方法?


我试着做以下,但我得到的警告,在注释规定:

+ (NSString *) myFormattedString:(NSString *)format, ... { 
    char *buffer; 
    [format getCString:buffer maxLength:[format length] encoding:NSASCIIStringEncoding]; 

    va_list args; 
    va_start(args, buffer); // WARNING: second parameter of 'va_start' not last named argument 

    NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; 
    [str autorelease]; 

    return [NSString stringWithFormat:@"Foo: %@.", str]; 
} 

我假设的va_start(原因)可以在一个(字符*)是因为我在 manual page of STDARG(3)上看到的例子。如果我完全错了,随意彻底重写该方法。

回答

15

我想你想的是一样的东西:

+ (NSString *) myFormattedString:(NSString *)format, ... { 
    va_list args; 
    va_start(args, format); 
    NSString *str = [[[NSString alloc] initWithFormat:format arguments:args] autorelease]; 
    va_end(args); 
    return [NSString stringWithFormat:@"Foo: %@.", str]; 
} 

stdarg.hva_ *宏用于当一个函数(或者,在这种情况下,法)采用可变数量的参数,如规定“ ...“。 va_start()用于查找可变数量参数开始的起点。因此,它需要知道函数/方法的最后一个参数(即“...”之前的那个),以确定变量的参数开始位置。这是一个有点简单的解释,因为实际发生的情况非常符合ABI /编译器特定的要求。最重要的一点是,va_start()的第二个参数始终是“...”之前的变量名称。

va_end()应该是“调用”(它实际上是一个宏,而不是函数),以实现最大的可移植性。再次,这整个可变的论证事物是深沉的,黑暗的魔法。根据编译器和ABI的具体情况,va_end()可能根本不会做任何事情。另一方面,如果使用va_end()失败,则可能会导致程序在达到return语句时崩溃,因为堆栈帧(如果有的话)不再适当地设置为实际执行返回。

+0

Woops,我误解了va_start()的工作原理。我想http://numbergrinder.com/node/35没有足够清楚地解释它。我认为va_start()的第二个参数是有多少个参数发送给函数的实际计数;并且它有一个'重载',它接受了一个格式字符串,该格式字符串根据格式字符串中有多少未转义的%确定了计数。哇,这使得它更容易,您不必确定你自己数。感谢您的解释。 – Senseful 2009-07-30 22:04:23

8

你已经差不多了;只是一些调整:

+ (NSString *) myFormattedString:(NSString *)format, ... { 
    va_list args; 
    va_start(args, format); 

    NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; 
    [str autorelease]; 

    va_end(args); 

    return [NSString stringWithFormat:@"Foo: %@.", str]; 
} 

这应该做你想要的。

相关问题