div*_*ges 5 string macros objective-c ios
我正在使用宏来简化返回本地化字符串,如下所示:
#define GetLocalStr(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil], ##__VA_ARGS__]
Run Code Online (Sandbox Code Playgroud)
基本上,如果您在本地化字符串文件中有一个条目,如"name" = "My name is %@";调用
GetLocalStr( @"name", @"Foo" );
Run Code Online (Sandbox Code Playgroud)
将返回NSString @"My name is Foo"
然而,当我运行它时,如:
NSString * str = GetLocalStr( @"name", @"Foo" );
Run Code Online (Sandbox Code Playgroud)
我得到"格式字符串不是字符串文字"警告.即使遵循关于此警告的其他答案的建议并将其替换为:
NSString * str = [NSString stringWithFormat:@"%@", GetLocalStr( @"name", @"Foo" )];
Run Code Online (Sandbox Code Playgroud)
我仍然得到警告,此外,它有点打破宏观使生活更容易的点.
如何摆脱GetLocalStr#pragma suppressors中包含所有调用的警告?
编辑27/08
在通过CRD的答案并进行更多测试之后,似乎我对错误做了一个错误的假设.澄清:
本地化字符串文件:
"TestNoArgs" = "Hello world";
"TestArgs" = "Hello world %@";
Run Code Online (Sandbox Code Playgroud)
码:
NSString * str1 = GetLocalStr( @"TestNoArgs" ); // gives warning
NSString * str2 = GetLocalStr( @"TestArgs", @"Foo" ); // doesn't give warning
Run Code Online (Sandbox Code Playgroud)
我的大部分翻译都没有参数,而那些是提供警告的,但在我阅读CRD的答案之前我没有建立联系.
我把我的单个宏改为两个,就像这样:
#define GetLocalStrNoArgs(key) \
[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil]
#define GetLocalStrArgs(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil], ##__VA_ARGS__]
Run Code Online (Sandbox Code Playgroud)
如果我分别给每个人打电话,那就没有警告了.
我想GetLocalStr扩展到任何一个GetLocalStrNoArgs或GetLocalStrArgs取决于是否传递任何参数,但到目前为止我一直没有运气(宏不是我的强项:D).
我sizeof(#__VA_ARGS__)用来确定是否传递了任何参数 - 它对参数进行了字符串化,如果大小为1,则它是空的(即"\ 0").也许这不是最理想的方法,但似乎有效.
如果我将我的GetLocalStr宏重写为:
#define GetLocalStr(key,...) (sizeof(#__VA_ARGS__) == 1) ? GetLocalStrNoArgs(key) : GetLocalStrArgs(key,##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
我可以使用它,但是我仍然会在它使用的任何地方得到警告,并且没有传递任何参数,而类似的东西
#define GetLocalStr( key,...) \
#if ( sizeof(#__VA_ARGS__) == 1 ) \
GetLocalStrNoArgs(key) \
#else \
GetLocalStrArgs(key,##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
不会编译.如何让我的GetLocalStr宏正确扩展?
Clang和GCC编译器检查格式字符串和提供的参数是否一致,如果格式字符串不是文字,则它们不能这样做 - 因此,当您从包中获取格式字符串时,您会看到错误消息.
为了解决这个问题,有一个属性format_arg(n)(docs)来标记带有格式字符串的函数; 在不改变实际格式说明符的情况下以某种方式改变它,例如翻译它; 然后返回它.Cocoa NS_FORMAT_ARG(n)为此属性提供了方便的宏.
要解决您的问题,您需要做两件事:
NSBundle在指定此属性的函数中结束调用; 和
更改"密钥"以包含格式说明符.
其次,您的字符串文件应包含:
"name %@" = "My name is %@"
Run Code Online (Sandbox Code Playgroud)
所以键具有与结果相同的格式说明符(如果需要重新排序特定语言的说明符,则使用位置格式说明符).
现在定义一个简单的函数来进行查找,将其归为格式转换函数.注意我们将其标记为static inline,使用宏NS_INLINE作为编译器的提示,将其内联到宏扩展中; 将static允许你把它列入无符号冲突多个文件:
NS_INLINE NSString *localize(NSString *string) NS_FORMAT_ARGUMENT(1);
NSString *localize(NSString *string)
{
return [[NSBundle mainBundle] localizedStringForKey:string value:@"" table:nil];
}
Run Code Online (Sandbox Code Playgroud)
你的宏变成了:
#define GetLocalStr(key, ...) [NSString stringWithFormat:localize(key), ##__VA_ARGS__]
Run Code Online (Sandbox Code Playgroud)
现在当你:
GetLocalStr(@"name %@", @"Foo")
Run Code Online (Sandbox Code Playgroud)
您将获得本地化格式字符串和格式检查.
更新
在Greg的评论之后我回去检查了 - 我已经重现了你的错误,因此认为它归结为一个缺失的属性.但是正如Greg指出的那样localizedStringForKey:value:table:已经有了属性,为什么会出错?我在重现你的错误时心不在焉的是:
NSLog( GetLocalStr( @"name %@", @"Foo" ) );
Run Code Online (Sandbox Code Playgroud)
并且编译器指向宏定义而不是那一行 - 我应该发现编译器误导了我.
那么你离开了哪里?也许你做过类似的事情?关键是格式字符串必须是文字或属于格式转换函数的函数/方法的结果.不要忘记,您还必须具有上述密钥的格式说明符.
更新2
在您的附加注释之后,您需要使用的是函数,而不是宏,以及formatCocoa为其提供方便NS_FORMAT_FUNCTION(f,a)宏的属性.此属性通知编译器该函数是格式化函数,值f是格式字符串的编号,是格式a的第一个参数的编号.这给出了函数声明:
NSString *GetLocalStr(NSString *key, ...) NS_FORMAT_FUNCTION(1,2);
Run Code Online (Sandbox Code Playgroud)
和定义(假设ARC):
NSString *GetLocalStr(NSString *key, ...)
{
va_list args;
va_start(args, key);
NSString *format = [[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil];
NSString *result = [[NSString alloc] initWithFormat:format arguments:args];
va_end (args);
return result;
}
Run Code Online (Sandbox Code Playgroud)
(这与@ A-Live的基本相同).
将适当检查其使用情况,例如:
int x;
...
NSString *s1 = GetLocalStr(@"name = %d", x); // OK
NSString *s2 = GetLocalStr(@"name = %d"); // compile warning - More '%" conversions than data arguments
NSString *s3 = GetLocalStr(@"name", x); // compile warning - Data argument not used by format string
NSString *s4 = GetLocalStr(@"name"); // OK
Run Code Online (Sandbox Code Playgroud)
此变体不会产生警告(因为总是有va_list):
NSString* GetLocalStr1(NSString *formatKey, ...) {
va_list ap;
va_start(ap, formatKey);
NSString * format = [[NSBundle mainBundle] localizedStringForKey:formatKey value:@"" table:nil];
NSString *result = [[NSString alloc] initWithFormat:format arguments:ap];
va_end (ap);
return [result autorelease];
}
...
__unused NSString * str = GetLocalStr1( @"name", @"Foo" );
__unused NSString * str1 = GetLocalStr1( @"TestNoArgs" );
__unused NSString * str2 = GetLocalStr1( @"TestArgs", @"Foo" );
NSLog(@"%@", str);
NSLog(@"%@", str1);
NSLog(@"%@", str2);
Run Code Online (Sandbox Code Playgroud)
结果:
我叫Foo
TestNoArgs
你好世界Foo
它没有准确回答问题,但可能会帮助您避免警告,直到找到解决方案.
| 归档时间: |
|
| 查看次数: |
8992 次 |
| 最近记录: |