0

In our current implementation we want to change our string arguments (Push notification loc-args) and add new arguments. But we want user's of our old Versions to still use argument #3 and for new user's we want to user argument #4. So in our new implementation we have following code :

NSString *format = @"%2$@,  %1$@  ,%4$@";
NSArray *arg = @[@"Argument 1", @"Argument 2",@"Argument 3",@"Argument 4"];
NSString *ouptput = [NSString stringWithFormat:format, arg[0], arg[1], arg[2], arg[3]];

OutPut: Argument 2, Argument 1 ,Argument 3

We are expecting it to be

Argument 2, Argument 1 ,Argument 4

How can we achieve Argument 4 in place. Any other alternative of stringWithFormat:

Note: Apple lock screen push notification is correct (Argument 2, Argument 1 ,Argument 4) but stringWithFormat: not handles it that way

Muhammad Nabeel Arif
  • 19,140
  • 8
  • 51
  • 70
  • "old versions"? of what? If it's an app, then how would old versions even see the changes? – trojanfoe Dec 31 '15 at 12:56
  • Actually arguments are sent via push notifications, so if we change arguments, 'Old Version' apps will get updated argument list. Only format is in the app. – Muhammad Nabeel Arif Dec 31 '15 at 12:58
  • See http://stackoverflow.com/questions/2944704/advanced-localization-with-omission-of-arguments-in-xcode: *"When numbered argument specifications are used, specifying the Nth argument **requires** that all the leading arguments, from the first to the (N-1)th, are specified in the format string."* – If you omit the 3rd argument in the format string then the behaviour is undefined. – Martin R Dec 31 '15 at 14:08
  • @MartinR you are right. But apple handles it. When presenting push notification, it will be displayed as `Argument 2, Argument 1 ,Argument 4` on lock screen for above format and arguments. And I want to achieve the same within the app as well – Muhammad Nabeel Arif Dec 31 '15 at 18:14
  • Here is another workaround: http://stackoverflow.com/questions/2946649/nsstring-stringwithformat-swizzled-to-allow-missing-format-numbered-args. – Martin R Dec 31 '15 at 18:43
  • An external suggestion: Pass the version number of the app to the web service database while registering for remote notifications and send the payload depending on the version (you will get 0 or `nil` for the old versions). – vadian Dec 31 '15 at 18:58

1 Answers1

0

I implemented a custom method to achieve expected output. This method can handle missing positional specifier. This method will only work for format containing positional specifier %n$@.

/**
 @param format String format with positional specifier
 @param arg Array of arguments to replace positional specifier in format
 @return Formatted output string
 */
+(NSString*)stringWithPositionalSpecifierFormat:(NSString*)format arguments:(NSArray*)arg
{
    static NSString *pattern = @"%\\d\\$@";

    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];

    NSMutableString *mString = [[NSMutableString alloc] initWithString:format];
    NSArray *allMatches = [regex matchesInString:format options:0 range:NSMakeRange(0, [format length])];
    if (!error && allMatches>0)
    {
        for (NSTextCheckingResult *aMatch in allMatches)
        {
            NSRange matchRange = [aMatch range];
            NSString *argPlaceholder = [format substringWithRange:matchRange];
            NSMutableString *position = [argPlaceholder mutableCopy];
            [position replaceOccurrencesOfString:@"%" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [position length])];
            [position replaceOccurrencesOfString:@"$@" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [position length])];
            int index = position.intValue;
            //Replace with argument
            [mString replaceOccurrencesOfString:argPlaceholder withString:arg[index-1] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [mString length])];
        }
    }
    return mString;
}
Muhammad Nabeel Arif
  • 19,140
  • 8
  • 51
  • 70