objective-c 在 ObjectiveC 中从 NSDictionary 对象创建 URL 查询参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/718429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating URL query parameters from NSDictionary objects in ObjectiveC
提问by Joe Masilotti
With all the URL-handling objects lying around in the standard Cocoa libraries (NSURL, NSMutableURL, NSMutableURLRequest, etc), I know I must be overlooking an easy way to programmatically compose a GET request.
所有 URL 处理对象都位于标准 Cocoa 库(NSURL、NSMutableURL、NSMutableURLRequest 等)中,我知道我必须忽略以编程方式编写 GET 请求的简单方法。
Currently I'm manually appending "?" followed by name value pairs joined by "&", but all of my name and value pairs need to be manually encoded so NSMutableURLRequest doesn't fail entirely when it tries to connect to the URL.
目前我正在手动附加“?” 后跟由“&”连接的名称值对,但我所有的名称和值对都需要手动编码,因此 NSMutableURLRequest 在尝试连接到 URL 时不会完全失败。
This feels like something I should be able to use a pre-baked API for.... is there anything out of the box to append an NSDictionary of query parameters to an NSURL? Is there another way I should approach this?
这感觉就像我应该能够使用预烘焙 API 的东西......是否有任何开箱即用的东西可以将查询参数的 NSDictionary 附加到 NSURL?还有另一种方法我应该解决这个问题吗?
回答by Joe Masilotti
Introduced in iOS8 and OS X 10.10 is NSURLQueryItem, which can be used to build queries. From the docs on NSURLQueryItem:
在 iOS8 和 OS X 10.10 中引入的是NSURLQueryItem,可用于构建查询。从NSURLQueryItem上的文档:
An NSURLQueryItem object represents a single name/value pair for an item in the query portion of a URL. You use query items with the queryItems property of an NSURLComponents object.
NSURLQueryItem 对象表示 URL 查询部分中项目的单个名称/值对。您可以将查询项与 NSURLComponents 对象的 queryItems 属性一起使用。
To create one use the designated initializer queryItemWithName:value:and then add them to NSURLComponentsto generate an NSURL. For example:
要创建一个使用指定的初始化程序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
Notice that the question mark and ampersand are automatically handled. Creating an NSURLfrom a dictionary of parameters is as simple as:
请注意,问号和与号是自动处理的。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;
I've also written a blog poston how to build URLs with NSURLComponentsand NSURLQueryItems.
回答by Don McCaughey
You can create a category for NSDictionaryto do this -- there isn't a standard way in the Cocoa library that I could find either. The code that I use looks like this:
您可以NSDictionary为此创建一个类别——我也找不到可可库中的标准方法。我使用的代码如下所示:
// file "NSDictionary+UrlEncoding.h"
#import <cocoa/cocoa.h>
@interface NSDictionary (UrlEncoding)
-(NSString*) urlEncodedString;
@end
with this implementation:
使用此实现:
// 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
I think the code's pretty straightforward, but I discuss it in some more detail at http://blog.ablepear.com/2008/12/urlencoding-category-for-nsdictionary.html.
我认为代码非常简单,但我在http://blog.ablepear.com/2008/12/urlencoding-category-for-nsdictionary.html 上更详细地讨论了它。
回答by Anonymous Dev
I wanted to use Chris's answer, but it wasn't written for Automatic Reference Counting(ARC) so I updated it. I thought I'd paste my solution in case anyone else has this same issue. Note:replace selfwith the instance or class name where appropriate.
我想使用 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;
}
回答by AlBeebe
The other answers work great if the values are strings, however if the values are dictionaries or arrays then this code will handle that.
如果值是字符串,则其他答案效果很好,但是如果值是字典或数组,则此代码将处理该问题。
Its important to note that there is no standard way of passing an array/dictionary via the query string but PHP handles this output just fine
需要注意的是,没有通过查询字符串传递数组/字典的标准方法,但 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:@"&"];
}
Examples
例子
[foo] => bar
[translations] =>
{
[one] => uno
[two] => dos
[three] => tres
}
foo=bar&translations[one]=uno&translations[two]=dos&translations[three]=tres
foo=bar&translations[one]=uno&translations[two]=dos&translations[three]=tres
[foo] => bar
[translations] =>
{
uno
dos
tres
}
foo=bar&translations[]=uno&translations[]=dos&translations[]=tres
foo=bar&translations[]=uno&translations[]=dos&translations[]=tres
回答by Renetik
I refactored and converted to ARC answer by AlBeebe
我重构并转换为 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);
}
回答by Ayush Goel
If you are already using AFNetworking(as was the case with me), you can use it's class AFHTTPRequestSerializerto create the required NSURLRequest.
如果您已经在使用AFNetworking(就像我的情况),您可以使用它的类AFHTTPRequestSerializer来创建所需的NSURLRequest.
[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:@"YOUR_URL" parameters:@{PARAMS} error:nil];
[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:@"YOUR_URL" parameters:@{PARAMS} error:nil];
In case you only require the URL for your work, use NSURLRequest.URL.
如果您只需要工作的 URL,请使用NSURLRequest.URL.
回答by Zorayr
Here is a simple example in Swift(iOS8+):
这是Swift(iOS8+) 中的一个简单示例:
private let kSNStockInfoFetchRequestPath: String = "http://dev.markitondemand.com/Api/v2/Quote/json"
private func SNStockInfoFetchRequestURL(symbol:String) -> NSURL? {
if let components = NSURLComponents(string:kSNStockInfoFetchRequestPath) {
components.queryItems = [NSURLQueryItem(name:"symbol", value:symbol)]
return components.URL
}
return nil
}
回答by Can
I took Joel's recommendation of using URLQueryItemsand turned into a Swift Extension (Swift 3)
我接受了 Joel 的使用建议URLQueryItems并变成了 Swift 扩展(Swift 3)
extension URL
{
/// Creates an NSURL with url-encoded parameters.
init?(string : String, parameters : [String : String])
{
guard var components = URLComponents(string: string) else { return nil }
components.queryItems = parameters.map { return URLQueryItem(name: URL(string: "http://www.google.com/", parameters: ["q" : "search me"])
, value: ) }
guard let url = components.url else { return nil }
// Kinda redundant, but we need to call init.
self.init(string: url.absoluteString)
}
}
(The self.initmethod is kinda cheesy, but there was no NSURLinit with components)
(该self.init方法有点俗气,但没有NSURL带组件的初始化)
Can be used as
可以用作
+(NSString*)urlEscape:(NSString *)unencodedString {
NSString *s = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
kCFStringEncodingUTF8);
return [s autorelease]; // Due to the 'create rule' we own the above and must autorelease it
}
// Put a query string onto the end of a url
+(NSString*)addQueryStringToUrl:(NSString *)url params:(NSDictionary *)params {
NSMutableString *urlWithQuerystring = [[[NSMutableString alloc] initWithString:url] autorelease];
// Convert the params into a query string
if (params) {
for(id key in params) {
NSString *sKey = [key description];
NSString *sVal = [[params objectForKey:key] description];
// Do we need to add ?k=v or &k=v ?
if ([urlWithQuerystring rangeOfString:@"?"].location==NSNotFound) {
[urlWithQuerystring appendFormat:@"?%@=%@", [Http urlEscape:sKey], [Http urlEscape:sVal]];
} else {
[urlWithQuerystring appendFormat:@"&%@=%@", [Http urlEscape:sKey], [Http urlEscape:sVal]];
}
}
}
return urlWithQuerystring;
}
回答by Chris
I've got another solution:
我有另一个解决方案:
http://splinter.com.au/build-a-url-query-string-in-obj-c-from-a-dict
http://splinter.com.au/build-a-url-query-string-in-obj-c-from-a-dict
NSDictionary *params = @{@"username":@"jim", @"password":@"abc123"};
NSString *urlWithQuerystring = [self addQueryStringToUrl:@"https://myapp.com/login" params:params];
You can then use it like so:
然后你可以像这样使用它:
-(NSString*)encodeDictionary:(NSDictionary*)dictionary{
NSMutableString *bodyData = [[NSMutableString alloc]init];
int i = 0;
for (NSString *key in dictionary.allKeys) {
i++;
[bodyData appendFormat:@"%@=",key];
NSString *value = [dictionary valueForKey:key];
NSString *newString = [value stringByReplacingOccurrencesOfString:@" " withString:@"+"];
[bodyData appendString:newString];
if (i < dictionary.allKeys.count) {
[bodyData appendString:@"&"];
}
}
return bodyData;
}

