由于所有的URL处理对象都位于标准的Cocoa库(NSURL,NSMutableURL,NSMutableURLRequest等)中,我知道我必须忽略一种以编程方式编写GET请求的简单方法.
目前我手动追加"?" 后跟由"&"连接的名称值对,但我的所有名称和值对都需要手动编码,因此NSMutableURLRequest在尝试连接到URL时不会完全失败.
这感觉就像我应该能够使用预先出炉的API ......是否有任何开箱即可将查询参数的NSDictionary附加到NSURL?我还有另一种方法吗?
在iOS8和OS X 10.10中引入NSURLQueryItem
,可用于构建查询.从NSURLQueryItem上的文档:
NSURLQueryItem对象表示URL的查询部分中的项的单个名称/值对.您将查询项与NSURLComponents对象的queryItems属性一起使用.
要创建一个使用指定的初始化程序queryItemWithName:value:
,然后将它们添加NSURLComponents
到生成NSURL
.例如:
NSURLComponents *components = [NSURLComponents componentsWithString:@"http://stackoverflow.com"]; NSURLQueryItem *search = [NSURLQueryItem queryItemWithName:@"q" value:@"ios"]; NSURLQueryItem *count = [NSURLQueryItem queryItemWithName:@"count" value:@"10"]; components.queryItems = @[ search, count ]; NSURL *url = components.URL; // http://stackoverflow.com?q=ios&count=10
请注意,问号和&符号会自动处理.NSURL
从参数字典创建一个简单如下:
NSDictionary *queryDictionary = @{ @"q": @"ios", @"count": @"10" }; NSMutableArray *queryItems = [NSMutableArray array]; for (NSString *key in queryDictionary) { [queryItems addObject:[NSURLQueryItem queryItemWithName:key value:queryDictionary[key]]]; } components.queryItems = queryItems;
我还写了一篇关于如何用NSURLComponents
和构建URL 的博客文章NSURLQueryItems
.
您可以创建一个类别NSDictionary
来执行此操作 - 在Cocoa库中没有我可以找到的标准方法.我使用的代码如下所示:
// file "NSDictionary+UrlEncoding.h" #import@interface NSDictionary (UrlEncoding) -(NSString*) urlEncodedString; @end
有了这个实现:
// file "NSDictionary+UrlEncoding.m" #import "NSDictionary+UrlEncoding.h" // helper function: get the string form of any object static NSString *toString(id object) { return [NSString stringWithFormat: @"%@", object]; } // helper function: get the url encoded string form of any object static NSString *urlEncode(id object) { NSString *string = toString(object); return [string stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; } @implementation NSDictionary (UrlEncoding) -(NSString*) urlEncodedString { NSMutableArray *parts = [NSMutableArray array]; for (id key in self) { id value = [self objectForKey: key]; NSString *part = [NSString stringWithFormat: @"%@=%@", urlEncode(key), urlEncode(value)]; [parts addObject: part]; } return [parts componentsJoinedByString: @"&"]; } @end
我认为代码非常简单,但我在http://blog.ablepear.com/2008/12/urlencoding-category-for-nsdictionary.html上更详细地讨论了它.
我想使用Chris的答案,但它不是为自动引用计数(ARC)编写的,所以我更新了它.我以为我会粘贴我的解决方案以防其他人有同样的问题. 注意:self
在适当的地方替换实例或类名.
+(NSString*)urlEscapeString:(NSString *)unencodedString { CFStringRef originalStringRef = (__bridge_retained CFStringRef)unencodedString; NSString *s = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,originalStringRef, NULL, (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ", kCFStringEncodingUTF8); CFRelease(originalStringRef); return s; } +(NSString*)addQueryStringToUrlString:(NSString *)urlString withDictionary:(NSDictionary *)dictionary { NSMutableString *urlWithQuerystring = [[NSMutableString alloc] initWithString:urlString]; for (id key in dictionary) { NSString *keyString = [key description]; NSString *valueString = [[dictionary objectForKey:key] description]; if ([urlWithQuerystring rangeOfString:@"?"].location == NSNotFound) { [urlWithQuerystring appendFormat:@"?%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]]; } else { [urlWithQuerystring appendFormat:@"&%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]]; } } return urlWithQuerystring; }
如果值是字符串,则其他答案很有效,但是如果值是字典或数组,则此代码将处理该字符串.
重要的是要注意,没有通过查询字符串传递数组/字典的标准方法,但PHP处理此输出就好了
-(NSString *)serializeParams:(NSDictionary *)params { /* Convert an NSDictionary to a query string */ NSMutableArray* pairs = [NSMutableArray array]; for (NSString* key in [params keyEnumerator]) { id value = [params objectForKey:key]; if ([value isKindOfClass:[NSDictionary class]]) { for (NSString *subKey in value) { NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)[value objectForKey:subKey], NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); [pairs addObject:[NSString stringWithFormat:@"%@[%@]=%@", key, subKey, escaped_value]]; } } else if ([value isKindOfClass:[NSArray class]]) { for (NSString *subValue in value) { NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)subValue, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); [pairs addObject:[NSString stringWithFormat:@"%@[]=%@", key, escaped_value]]; } } else { NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)[params objectForKey:key], NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]]; [escaped_value release]; } } return [pairs componentsJoinedByString:@"&"]; }
例子
[foo] => bar [translations] => { [one] => uno [two] => dos [three] => tres }
富=酒吧和翻译[酮] = UNO&翻译[2] =&DOS翻译[3] = TRES
[foo] => bar [translations] => { uno dos tres }
富=酒吧和翻译[] = UNO&翻译[] = DOS&翻译[] = TRES
我重构并转换为AlBeebe的ARC回答
- (NSString *)serializeParams:(NSDictionary *)params { NSMutableArray *pairs = NSMutableArray.array; for (NSString *key in params.keyEnumerator) { id value = params[key]; if ([value isKindOfClass:[NSDictionary class]]) for (NSString *subKey in value) [pairs addObject:[NSString stringWithFormat:@"%@[%@]=%@", key, subKey, [self escapeValueForURLParameter:[value objectForKey:subKey]]]]; else if ([value isKindOfClass:[NSArray class]]) for (NSString *subValue in value) [pairs addObject:[NSString stringWithFormat:@"%@[]=%@", key, [self escapeValueForURLParameter:subValue]]]; else [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, [self escapeValueForURLParameter:value]]]; } return [pairs componentsJoinedByString:@"&"];
}
- (NSString *)escapeValueForURLParameter:(NSString *)valueToEscape { return (__bridge_transfer NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef) valueToEscape, NULL, (CFStringRef) @"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); }
如果您已经在使用AFNetworking(就像我的情况一样),您可以使用它的类AFHTTPRequestSerializer
来创建所需的NSURLRequest
.
[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:@"YOUR_URL" parameters:@{PARAMS} error:nil];
如果您只需要工作的URL,请使用NSURLRequest.URL
.