Skip to content

Instantly share code, notes, and snippets.

@mramsden
Created May 14, 2011 15:38
Show Gist options
  • Save mramsden/972328 to your computer and use it in GitHub Desktop.
Save mramsden/972328 to your computer and use it in GitHub Desktop.
Creating a query string from an NSDictionary.
NSDictionary *queryParameters = [NSDictionary dictionaryWithValuesAndKeys:1, @"page", nil, @"enabled", 25, @"size", nil];
[queryParameters queryString]; // This will return "?page=1&enabled&size=25"
#import <Foundation/Foundation.h>
@interface NSDictionary (QueryStringBuilder)
- (NSString *)queryString;
@end
#import "NSDictionary+QueryStringBuilder.h"
static NSString * escapeString(NSString *unencodedString)
{
NSString *s = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
kCFStringEncodingUTF8);
return [s autorelease];
}
@implementation NSDictionary (QueryStringBuilder)
- (NSString *)queryString
{
NSMutableString *queryString = nil;
NSArray *keys = [self allKeys];
if ([keys count] > 0) {
for (id key in keys) {
id value = [self objectForKey:key];
if (nil == queryString) {
queryString = [[[NSMutableString alloc] init] autorelease];
[queryString appendFormat:@"?"];
} else {
[queryString appendFormat:@"&"];
}
if (nil != key && nil != value) {
[queryString appendFormat:@"%@=%@", escapeString(key), escapeString(value)];
} else if (nil != key) {
[queryString appendFormat:@"%@", escapeString(key)];
}
}
}
return queryString;
}
@end
@ehabkost
Copy link

The argument name for escapeString() should be unencodedString instead of string, as this is the name used on the CFURLCreateStringByAddingPercentEscapes call. My fork of this gist fixes this so the code compiles.

It also makes escapeString() a static function to avoid compiler warnings.

@mramsden
Copy link
Author

Thanks for the spots :)

@bigpandras
Copy link

id value = [self objectForKey:key]
if value was NSArray, what would happen?

@mramsden
Copy link
Author

@bigpandras that's a good question, with a bit of a lengthy answer.

To answer your question. At the moment I would assume that there would be a crash since there is nothing special handling an array vs. a string. The call to escapeString expects an NSString * to be passed, so if you passed an NSArray * I would expect a crash or some other undefined behaviour as without running this code I'm not sure what happens if you cast an NSArray to a CFStringRef.

All of that being said I would strongly encourage you to have a look at NSURLComponents and specifically the queryItems property. Since I used this snippet Apple has now added some supported API although it is based on the key and value both being strings.

Realistically if you wanted to use this code or Apple's you would need to establish how your API handles an array of values for a query parameter. I can think of a number of different scenarios:

  1. Joining an array with a series of comma separated values
  2. Repeating your key name e.g. key=value1&key=value2

This entirely depends on how the API works you are trying to use expects these parameters. I hope that helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment