Objective-C: How to add query parameter to NSURL?
Let's say I have an NSURL
? Whether or not it already has an empty query string, how do I add one or more parameters to the query
of the NSURL
? I.e., does anyone know of an implementation of this function?
- (NSURL *)URLByAppendingQueryString:(NSString *)queryString
So that it satisfies this NSURL+AdditionsSpec.h
file:
#import "NSURL+Additions.h"
#import "Kiwi.h"
SPEC_BEGIN(NSURL_AdditionsSpec)
describe(@"NSURL+Additions", ^{
__block NSURL *aURL;
beforeEach(^{
aURL = [[NSURL alloc] initWithString:@"http://www.example.com"];
aURLWithQuery = [[NSURL alloc] initWithString:@"http://www.example.com?key=value"];
});
afterEach(^{
[aURL release];
[aURLWithQuery release];
});
describe(@"-URLByAppendingQueryString:", ^{
it(@"adds to plain URL", ^{
[[[[aURL URLByAppendingQueryString:@"key=value&key2=value2"] query] should]
equal:@"key=value&key2=value2"];
});
it(@"appends to the existing query sting", ^{
[[[[aURLWithQuery URLByAppendingQueryString:@"key2=value2&key3=value3"] query] should]
equal:@"key=value&key2=value2&key3=value3"];
});
});
});
SPEC_END
Since iOS 7 you can use NSURLComponents that is very simple to use. Take a look on these examples:
Example 1
NSString *urlString = @"https://mail.google.com/mail/u/0/?shva=1#inbox";
NSURLComponents *components = [[NSURLComponents alloc] initWithString:urlString];
NSLog(@"%@ - %@ - %@ - %@", components.scheme, components.host, components.query, components.fragment);
Example 2
NSString *urlString = @"https://mail.google.com/mail/u/0/?shva=1#inbox";
NSURLComponents *components = [[NSURLComponents alloc] initWithString:urlString];
if (components) {
//good URL
} else {
//bad URL
}
Example 3
NSURLComponents *components = [NSURLComponents new];
[components setScheme:@"https"];
[components setHost:@"mail.google.com"];
[components setQuery:@"shva=1"];
[components setFragment:@"inbox"];
[components setPath:@"/mail/u/0/"];
[self.webview loadRequest:[[NSURLRequest alloc] initWithURL:[components URL]]];
But you can do many other things with NSURLComponents take a look on NSURLComponents class reference on Apple documentation or on this link: http://nshipster.com/nsurl/
Here's an implementation that passes your specs:
@implementation NSURL (Additions)
- (NSURL *)URLByAppendingQueryString:(NSString *)queryString {
if (![queryString length]) {
return self;
}
NSString *URLString = [[NSString alloc] initWithFormat:@"%@%@%@", [self absoluteString],
[self query] ? @"&" : @"?", queryString];
NSURL *theURL = [NSURL URLWithString:URLString];
[URLString release];
return theURL;
}
@end
And here is an implementation for NSString
:
@implementation NSString (Additions)
- (NSURL *)URLByAppendingQueryString:(NSString *)queryString {
if (![queryString length]) {
return [NSURL URLWithString:self];
}
NSString *URLString = [[NSString alloc] initWithFormat:@"%@%@%@", self,
[self rangeOfString:@"?"].length > 0 ? @"&" : @"?", queryString];
NSURL *theURL = [NSURL URLWithString:URLString];
[URLString release];
return theURL;
}
// Or:
- (NSString *)URLStringByAppendingQueryString:(NSString *)queryString {
if (![queryString length]) {
return self;
}
return [NSString stringWithFormat:@"%@%@%@", self,
[self rangeOfString:@"?"].length > 0 ? @"&" : @"?", queryString];
}
@end
The iOS8+ modern way
adding (or replacing 'ref' value if exists) ref=impm to url which is on min60.com
if ([[url host] hasSuffix:@"min60.com"]) {
NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO];
NSURLQueryItem * newQueryItem = [[NSURLQueryItem alloc] initWithName:@"ref" value:@"impm"];
NSMutableArray * newQueryItems = [NSMutableArray arrayWithCapacity:[components.queryItems count] + 1];
for (NSURLQueryItem * qi in components.queryItems) {
if (![qi.name isEqual:newQueryItem.name]) {
[newQueryItems addObject:qi];
}
}
[newQueryItems addObject:newQueryItem];
[components setQueryItems:newQueryItems];
url = [components URL];
}