Question

I wrote a little NSString category with a better implementation of percent escaping for one of my projects: @im

plementation NSString (Escaping)
- (NSString *)stringByAddingSafePercentEscapesUsingEncoding:(NSStringEncoding)encoding
{
    NSRange wholeString = NSMakeRange(0, [self length]);
    NSMutableString *escaping = [NSMutableString stringWithString:[self stringByAddingPercentEscapesUsingEncoding:encoding]];
    [escaping replaceOccurrencesOfString:@"$" withString:@"%24" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"&" withString:@"%26" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"+" withString:@"%2B" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"," withString:@"%2C" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@":" withString:@"%3A" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@";" withString:@"%3B" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"-" withString:@"%2D" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"=" withString:@"%3D" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"?" withString:@"%3F" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"@" withString:@"%40" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@" " withString:@"%20" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"\t" withString:@"%09" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"#" withString:@"%23" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"<" withString:@"%3C" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@">" withString:@"%3E" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"\"" withString:@"%22" options:NSCaseInsensitiveSearch range:wholeString];
    [escaping replaceOccurrencesOfString:@"\n" withString:@"%0A" options:NSCaseInsensitiveSearch range:wholeString];
    NSString *escaped = [NSString stringWithString:escaping];

    return escaped;
}
@end

In this one project it works GREAT and I love to use it. But when I port it to another project, that code throughs an EXC_BAD_ACCESS. Could I make something better in that code?

Était-ce utile?

La solution

I just found my problem by accident:

Since the string effectively changes its length when replacing one characters by three characters, the string length changes with every replace. So the correct implementation for the category would be:

@implementation NSString (Escaping)
- (NSString *)stringByAddingSafePercentEscapesUsingEncoding:(NSStringEncoding)encoding
{
    NSRange wholeString = NSMakeRange(0, [self length]);
    NSMutableString *escaping = [NSMutableString stringWithString:[self stringByAddingPercentEscapesUsingEncoding:encoding]];
    [escaping replaceOccurrencesOfString:@"$" withString:@"%24" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"&" withString:@"%26" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"+" withString:@"%2B" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"," withString:@"%2C" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@":" withString:@"%3A" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@";" withString:@"%3B" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"-" withString:@"%2D" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"=" withString:@"%3D" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"?" withString:@"%3F" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"@" withString:@"%40" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@" " withString:@"%20" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"\t" withString:@"%09" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"#" withString:@"%23" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"<" withString:@"%3C" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@">" withString:@"%3E" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"\"" withString:@"%22" options:NSCaseInsensitiveSearch range:wholeString];
    wholeString = NSMakeRange(0, [escaping length]);
    [escaping replaceOccurrencesOfString:@"\n" withString:@"%0A" options:NSCaseInsensitiveSearch range:wholeString];
    NSString *escaped = [NSString stringWithString:escaping];

    return escaped;
}
@end

Autres conseils

I think it should be:

NSRange wholeString = NSMakeRange(0, [self length]-1);

You would get 'bad access' if your replaceOccurrencesOfString:withString:options:range: method iterates past the last character in the string.

Or you could use something like this for your replacement methods which already figures on iterating over the whole length. I am not sure what the default search option is however:

escaping = [escaping stringByReplacingOccurencesOfString:@"$" withString:@"%24"];
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top