NSString stringWithFormat swizzled允许缺少格式编号的args [英] NSString stringWithFormat swizzled to allow missing format numbered args

查看:152
本文介绍了NSString stringWithFormat swizzled允许缺少格式编号的args的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于这个问题问了几个小时以前,我决定实现一个混合方法,允许我将格式化的 NSString 作为格式arg转换为 stringWithFormat ,并且在省略其中一个编号的arg引用时不会中断(%1 $ @,%2 $ @

Based on this SO question asked a few hours ago, I have decided to implement a swizzled method that will allow me to take a formatted NSString as the format arg into stringWithFormat, and have it not break when omitting one of the numbered arg references (%1$@, %2$@)

我有它工作,但这是第一个副本,并且看到这个方法可能会被称为每个应用程序运行数十万次,我需要从一些专家那里反弹,看看这个方法是否有任何危险信号,主要性能点击或优化

I have it working, but this is the first copy, and seeing as this method is going to be potentially called hundreds of thousands of times per app run, I need to bounce this off of some experts to see if this method has any red flags, major performance hits, or optimizations

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
@implementation NSString (UAFormatOmissions)
+ (id)uaStringWithFormat:(NSString *)format, ... {  
    if (format != nil) {
        va_list args;
        va_start(args, format);

        // $@ is an ordered variable (%1$@, %2$@...)
        if ([format rangeOfString:@"$@"].location == NSNotFound) {
            //call apples method
            NSString *s = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
            va_end(args);
            return s;
        }

        NSMutableArray *newArgs = [NSMutableArray arrayWithCapacity:NUMARGS(args)];
        id arg = nil;
        int i = 1;
        while (arg = va_arg(args, id)) {
            NSString *f = [NSString stringWithFormat:@"%%%d\$\@", i];
            i++;
            if ([format rangeOfString:f].location == NSNotFound) continue;
            else [newArgs addObject:arg];
        }
        va_end(args);

        char *newArgList = (char *)malloc(sizeof(id) * [newArgs count]);
        [newArgs getObjects:(id *)newArgList];
        NSString* result = [[[NSString alloc] initWithFormat:format arguments:newArgList] autorelease];
        free(newArgList);
        return result;
    }
    return nil;
}

基本算法是:


  1. 搜索%1 $ @ 的格式字符串,%2 $ @ 变量通过搜​​索%@

  2. 如果找不到,请调用正常的stringWithFormat并返回

  3. 否则,循环遍历args

  4. 如果格式的位置变量(%i $ @ )为位置i,将arg添加到新的arg数组

  5. 否则,不要添加arg

  6. 获取新的arg数组,将其转换回 va_list ,并调用 initWithFormat:arguments:以获取正确的字符串。

  1. search the format string for the %1$@, %2$@ variables by searching for %@
  2. if not found, call the normal stringWithFormat and return
  3. else, loop over the args
  4. if the format has a position variable (%i$@) for position i, add the arg to the new arg array
  5. else, don't add the arg
  6. take the new arg array, convert it back into a va_list, and call initWithFormat:arguments: to get the correct string.

我的想法是通过这种方法运行所有 [NSString stringWithFormat:] 调用。

The idea is that I would run all [NSString stringWithFormat:] calls through this method instead.

对于许多人来说,这似乎是不必要的,但是点击引用的SO问题(第一行)以查看我需要这样做的示例。

This might seem unnecessary to many, but click on to the referenced SO question (first line) to see examples of why I need to do this.

想法?思考?更好的实施?更好的解决方案?

Ideas? Thoughts? Better implementations? Better Solutions?

推荐答案

如何定义自己的临时方法而不是使用格式说明符和 stringWithFormat:?例如,您可以定义自己的方法 replaceIndexPoints:以查找($ 1)而不是%1 $ @ 。然后,您将格式化您的字符串并独立插入已翻译的替换项。此方法还可以使用 NSNull 中的字符串数组或未翻译中不存在的索引处的空字符串。字符串。

How about defining your own interim method instead of using format specifiers and stringWithFormat:? For example, you could define your own method replaceIndexPoints: to look for ($1) instead of %1$@. You would then format your string and insert translated replacements independently. This method could also take an array of strings, with NSNull or empty strings at the indexes that don't exist in the “untranslated” string.

您的方法可能如下所示(如果它是 NSMutableString 的类别方法):

Your method could look like this (if it were a category method for NSMutableString):

- (void) replaceIndexPointsWithStrings:(NSArray *) replacements
{
    // 1. look for largest index in "self".
    // 2. loop from the beginning to the largest index, replacing each
    //    index with corresponding string from replacements array.
}

这是我在您当前实施中看到的一些问题(一目了然) :

Here's a few issues that I see with your current implementation (at a glance):


  1. 评论中解释了 __ VA_ARGS __ thingy。

  2. 当你使用 while(arg = va_arg(args,id))时,你假设参数是 nil 已终止(例如 arrayWithObjects:),但是 stringWithFormat:这不是必需的。

  3. 我认为你不需要逃避 $ @ 你的arg-loop中的字符串格式。

  4. 我不确定如果 uaStringWithFormat:被传递了大于指针(即 long long ,如果指针是32位)。如果您的翻译还需要插入长期幅度的非本地化数字,这可能只是一个问题。

  1. The __VA_ARGS__ thingy explained in the comments.
  2. When you use while (arg = va_arg(args, id)), you are assuming that the arguments are nil terminated (such as for arrayWithObjects:), but with stringWithFormat: this is not a requirement.
  3. I don't think you're required to escape the $ and @ in your string format in your arg-loop.
  4. I'm not sure this would work well if uaStringWithFormat: was passed something larger than a pointer (i.e. long long if pointers are 32-bit). This may only be an issue if your translations also require inserting unlocalised numbers of long long magnitude.

这篇关于NSString stringWithFormat swizzled允许缺少格式编号的args的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆