Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
@bigpandras
Copy link

bigpandras commented Dec 23, 2019

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

@mramsden
Copy link
Author

mramsden commented Dec 25, 2019

@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