1

I created a method to build URLs for me.

- (NSString *)urlFor:(NSString *)path arguments:(NSDictionary *)args
{
    NSString *format = @"http://api.example.com/%@?version=2.0.1";
    NSMutableString *url = [NSMutableString stringWithFormat:format, path];

    if ([args isKindOfClass:[NSDictionary class]]) {
        for (NSString *key in args) {
            [url appendString:[NSString stringWithFormat:@"&%@=%@", key, [args objectForKey:key]]];
        }
    }

    return url;
}

When I try to build something like below, the URLs aren't encoded, of course.

NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:
                            @"http://other.com", @"url",
                            @"ABCDEF", @"apiKey", nil];

NSLog(@"%@", [self urlFor:@"articles" arguments:args]);`

The returned value is http://api.example.com/articles?version=2.0.1&url=http://other.com&apiKey=ABCDEF when it should be http://api.example.com/articles?version=2.0.1&url=http%3A%2F%2Fother.com&apiKey=ABCDEF.

I need to encode both key and value. I searched for something and found CFURLCreateStringByAddingPercentEscapes and stringByAddingPercentEscapesUsingEncoding but none of the tests I made worked.

How can I do it?

user102008
  • 30,736
  • 10
  • 83
  • 104
Nando Vieira
  • 964
  • 10
  • 17

3 Answers3

3

IIRC, slashes should be interpreted properly when they're in the query part of a URL. Did you test to see if it still works without encoded slashses? Otherwise, do something like:

if ([args isKindOfClass:[NSDictionary class]]) {
        for (NSString *key in [args allKeys]) {
            NSString *value = [(NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)[args objectForKey:key], NULL, CFSTR("/?&:=#"), kCFStringEncodingUTF8) autorelease];
            [url appendString:[NSString stringWithFormat:@"&%@=%@", key, value]];
            [value release];
        }
}

return url;

Note the value of the 4th argument to CFURLCreateStringByAddingPercentEscapes.

Wevah
  • 28,182
  • 7
  • 83
  • 72
  • One question: the 4th argument can accept any character that need to be encoded? – Nando Vieira Aug 09 '09 at 01:34
  • Yes. From the documentation: legalURLCharactersToBeEscaped Legal characters to be escaped. Pass NULL to specify that no legal characters be replaced. There are only a few characters that would otherwise not be escaped, but I went the safe route because I was too lazy to look up which ones those were (though it'd probably be a good idea). – Wevah Aug 09 '09 at 07:57
  • 1
    This leaks memory. `value` is an owned object that is discarded without being released. – Dave DeLong Jan 19 '11 at 18:34
  • You're right; I'll edit it. Can't believe I blitzed that out… – Wevah Jan 19 '11 at 18:50
  • This is actually bad code (as of now). I think the memory stuff is a bit messed up. Check out this question for better/updated code: http://stackoverflow.com/questions/718429/creating-url-query-parameters-from-nsdictionary-objects-in-objectivec – Jonny May 08 '14 at 08:23
  • It's not bad; it's just old and pre-ARC. – Wevah May 09 '14 at 03:04
1

You should consider using Google Toolbox for Mac's GTMNSString+URLArguments; it's designed for exactly this purpose.

smorgan
  • 20,228
  • 3
  • 47
  • 55
0

I'd recommend our KSFileUtilities set of classes. Your example would then be:

- (NSString *)urlFor:(NSString *)path arguments:(NSDictionary *)args
{
    NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:args];
    [parameters setObject:@"2.0.1" forKey:@"version"];

    NSURL *result = [NSURL ks_URLWithScheme:@"http"
                                       host:@"api.example.com"
                                       path:path
                            queryParameters:parameters;

    return [result absoluteString];
}
Mike Abdullah
  • 14,933
  • 2
  • 50
  • 75