Objective-C:如何将查询参数添加到NSURL?

假设我有一个NSURL ? 无论它是否已经有一个空的查询string,如何添加一个或多个参数到NSURLquery ? 即,有没有人知道这个function的实现?

 - (NSURL *)URLByAppendingQueryString:(NSString *)queryString 

所以它满足这个NSURL+AdditionsSpec.h文件:

 #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 

iOS 7开始,您可以使用非常简单的NSURLComponents 。 看看这些例子:

例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); 

例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 } 

例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]]]; 

但是你可以用NSURLComponents做很多其他的事情来看一下Apple文档或者这个链接上的NSURLComponents类的引用: http ://nshipster.com/nsurl/

这是一个通过你的规格的实现:

 @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 

这里是一个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 

iOS8 +现代化的方式

添加(或replace'ref'值,如果存在的话)ref = impm到min60.com上的url

 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]; } 

只是一个友好的职位,为那些谁不想编写样板代码,而NSURLComponentsbuild设NSURL
自iOS8以来,我们有NSURLQueryItem帮助构buildURL请求快速发生。

我写了一个方便的类别来简化工作,您可以在这里抓取: URLQueryBuilder
下面是使用它的容易程度的例子:

 NSString *baseURL = @"https://google.com/search"; NSDictionary *items = @{ @"q" : @"arsenkin.com", @"hl" : @"en_US", @"lr" : @"lang_en" }; NSURL *URL = [NSURL ars_queryWithString:baseURL queryElements:items]; // https://google.com/search?q=arsenkin.com&hl=en_US&lr=lang_en 

如果您使用的是RestKit,它会提供NSString的附加function 。 其中之一是:

 - (NSString *)stringByAppendingQueryParameters:(NSDictionary *)queryParameters 

所以你可以这样做:

 NSDictionary *shopParams = [NSDictionary dictionaryWithKeysAndObjects: @"limit",@"20", @"location",@"latitude,longitude", nil]; NSString *pathWithQuery = [@"/api/v1/shops.json" stringByAppendingQueryParameters:shopParams] 

我有一个扩展NSURLComponents添加查询项目,在swift中:

 extension NSURLComponents { func appendQueryItem(name name: String, value: String) { var queryItems: [NSURLQueryItem] = self.queryItems ?? [NSURLQueryItem]() queryItems.append(NSURLQueryItem(name: name, value: value)) self.queryItems = queryItems } } 

要使用,

 let components = NSURLComponents(string: urlString)! components.appendQueryItem(name: "key", value: "value") 

NSURL不可变,所以你不能直接基于NSURL来实现这个function。 相反,您将不得不获取URL的string表示forms,将您的参数追加到该参数,然后创build一个新的NSURL。

这听起来不是一个好的解决scheme。 除非有充分的理由,否则最好是直到最后一刻才使用string,只有在完全形成请求时才创buildNSURL。

上面的答案提到NSURLComponents,这是一个很好的类来处理URL。

我的回答如下:

用NSURL创build一个类别,比如NSURL + Additions.h。 然后,添加以下方法并实现它。

 - (NSURL *)URLByAppendingQueryParameters:(NSDictionary *)queryParameters { if (queryParameters.count == 0) { return self; } NSArray *queryKeys = [queryParameters allKeys]; NSURLComponents *components = [[NSURLComponents alloc] initWithURL:self resolvingAgainstBaseURL:NO]; NSMutableArray * newQueryItems = [NSMutableArray arrayWithCapacity:1]; for (NSURLQueryItem * item in components.queryItems) { if (![queryKeys containsObject:item.name]) { [newQueryItems addObject:item]; } } for (NSString *key in queryKeys) { NSURLQueryItem * newQueryItem = [[NSURLQueryItem alloc] initWithName:key value:queryParameters[key]]; [newQueryItems addObject:newQueryItem]; } [components setQueryItems:newQueryItems]; return [components URL]; }