Objective c 从Objective中的NSDictionary对象创建URL查询参数

Objective c 从Objective中的NSDictionary对象创建URL查询参数,objective-c,nsurl,Objective C,Nsurl,标准Cocoa库(NSURL、NSMutableURL、NSMutableURLRequest等)中包含了所有URL处理对象,我知道我一定忽略了一种以编程方式编写GET请求的简单方法 目前,我正在手动添加“?”,后面是由“&”连接的名称-值对,但我所有的名称和值对都需要手动编码,以便NSMutableURLRequest在尝试连接到URL时不会完全失败 这感觉就像我应该能够使用预烘焙的API来。。。。是否有任何现成的方法可以将查询参数的NSDictionary附加到NSURL?还有其他方法吗?您

标准Cocoa库(NSURL、NSMutableURL、NSMutableURLRequest等)中包含了所有URL处理对象,我知道我一定忽略了一种以编程方式编写GET请求的简单方法

目前,我正在手动添加“?”,后面是由“&”连接的名称-值对,但我所有的名称和值对都需要手动编码,以便NSMutableURLRequest在尝试连接到URL时不会完全失败


这感觉就像我应该能够使用预烘焙的API来。。。。是否有任何现成的方法可以将查询参数的NSDictionary附加到NSURL?还有其他方法吗?

您可以为
NSDictionary
创建一个类别来实现这一点——我在Cocoa库中也找不到标准方法。我使用的代码如下所示:

// file "NSDictionary+UrlEncoding.h"
#import <cocoa/cocoa.h>

@interface NSDictionary (UrlEncoding)

-(NSString*) urlEncodedString;

@end

我认为代码非常简单,但我在上更详细地讨论了它。

我有另一个解决方案:

然后您可以这样使用它:

NSDictionary *params = @{@"username":@"jim", @"password":@"abc123"};

NSString *urlWithQuerystring = [self addQueryStringToUrl:@"https://myapp.com/login" params:params];

我想用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可以很好地处理这个输出

示例

[foo] => bar
[translations] => 
        {
            [one] => uno
            [two] => dos
            [three] => tres
        }
[foo] => bar
[translations] => 
        {
            uno
            dos
            tres
        }
foo=bar&translations[one]=uno&translations[two]=dos&translations[three]=tres

[foo] => bar
[translations] => 
        {
            [one] => uno
            [two] => dos
            [three] => tres
        }
[foo] => bar
[translations] => 
        {
            uno
            dos
            tres
        }

foo=bar&translations[]=uno&translations[]=dos&translations[]=tresI由Albebe重构并转换为ARC应答

[foo] => bar
[translations] => 
        {
            [one] => uno
            [two] => dos
            [three] => tres
        }
[foo] => bar
[translations] => 
        {
            uno
            dos
            tres
        }
- (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*)编码字典:(NSDictionary*)字典{
NSMutableString*bodyData=[[NSMutableString alloc]init];
int i=0;
for(NSString*字典中的键。所有键){
i++;
[bodyData appendFormat:@“%@=,key];
NSString*值=[字典值forkey:key];
NSString*newString=[value StringByReplacingOfString:@”“with String:@“+”];
[bodyData appendString:newString];
if(i在iOS8和OS X 10.10中引入的
NSURLQueryItem
,可用于构建查询。从以下文件:

NSURLQueryItem对象表示URL查询部分中某个项的单个名称/值对。将查询项与NSURLComponents对象的queryItems属性一起使用

要创建一个,请使用指定的初始值设定项
queryItemWithName:value:
,然后将它们添加到
NSURL组件
以生成一个
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
NSURLQueryItems
构建URL的文章,如果您已经在使用(就像我的情况一样),您可以使用它的类
AFHTTPRequestSerializer
来创建所需的
NSURLRequest

[[AFHTTPRequestSerializer]requestWithMethod:@“GET”URLString:@“YOUR_URL”参数:@{PARAMS}错误:nil];


如果您的工作只需要URL,请使用
NSURLRequest.URL

以下是Swift(iOS8+)中的一个简单示例:


还有一种解决方案,如果你使用,
RKURLEncodedSerialization
中有一个函数叫做
RKURLEncodedStringFromDictionaryWithEncoding
,它完全符合你的需要。

我采纳了Joel的建议,使用
URLQueryItems
,并将其转换为一个Swift扩展(Swift 3)

(self.init
方法有点俗气,但是没有带组件的
NSURL
init)

可用作

URL(string: "http://www.google.com/", parameters: ["q" : "search me"])

在Objective-c中将NSDictionary转换为url查询字符串的简单方法

例:名字=史蒂夫&中名=盖茨&姓氏=乔布斯&地址=加州帕洛阿尔托

    NSDictionary *sampleDictionary = @{@"first_name"         : @"Steve",
                                     @"middle_name"          : @"Gates",
                                     @"last_name"            : @"Jobs",
                                     @"address"              : @"Palo Alto, California"};

    NSMutableString *resultString = [NSMutableString string];
            for (NSString* key in [sampleDictionary allKeys]){
                if ([resultString length]>0)
                    [resultString appendString:@"&"];
                [resultString appendFormat:@"%@=%@", key, [sampleDictionary objectForKey:key]];
            }
NSLog(@"QueryString: %@", resultString);
希望会有帮助:)

如果您已经在使用,您可以使用其内置的序列化程序生成编码的URL

NSString *baseURL = @"https://api.app.com/parse";
NSDictionary *mutableParameters = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"true",@"option1", data, @"option2", token, @"token", @"3.0", @"app", nil];
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:baseURL parameters:mutableParameters error:nil];
NSString *urlPath = request.URL.absoluteString;
NSLog(@"%@", urlPath); // https://api.app.com/parse?option1=true&option2=datavalue&token=200%3ATEST%3AENCODE ....

注;这是对上述答案的扩展。编辑队列已满,因此无法添加到现有答案。

我认为这不起作用。具体地说,您使用的是StringByAddingPercentescapesusingEncode,它不会转义和,以及中指定的查询参数中必须转义的其他字符。考虑一下这个问题。这是正确的逃避:请在你的答案中张贴相关的代码,这个链接可能永远不会出现。对于最后的“否则”的情况,我给描述添加了一个调用,以便它为NStUnt提供字符串,而不是对长度的调用。“谢谢!回答得很好。但是,您应该将
CFURLCreateStringByAddingPercentEscapes
调用替换为
stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet-URLQueryAllowedCharacterSet]
这对我来说非常有效,但我更改了最后一行以包含一个?在第一个参数之前:
[NSString stringWithFormat:@”?%@,[pairs Components由字符串连接:@“&”]
我认为您应该替换
CFURLCreateStringByAddingPercentEscapes
调用
stringByAddingPercentEncodingWithAllowedCharacters:[NSCharac]‌​terSet URLQueryAllowedCharacterSet]
这不能正确编码名称或值中的特殊字符(空格除外)。我认为空格不应替换为+而应替换为%20,这是
URL(string: "http://www.google.com/", parameters: ["q" : "search me"])
    NSDictionary *sampleDictionary = @{@"first_name"         : @"Steve",
                                     @"middle_name"          : @"Gates",
                                     @"last_name"            : @"Jobs",
                                     @"address"              : @"Palo Alto, California"};

    NSMutableString *resultString = [NSMutableString string];
            for (NSString* key in [sampleDictionary allKeys]){
                if ([resultString length]>0)
                    [resultString appendString:@"&"];
                [resultString appendFormat:@"%@=%@", key, [sampleDictionary objectForKey:key]];
            }
NSLog(@"QueryString: %@", resultString);
NSString *baseURL = @"https://api.app.com/parse";
NSDictionary *mutableParameters = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"true",@"option1", data, @"option2", token, @"token", @"3.0", @"app", nil];
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:baseURL parameters:mutableParameters error:nil];
NSString *urlPath = request.URL.absoluteString;
NSLog(@"%@", urlPath); // https://api.app.com/parse?option1=true&option2=datavalue&token=200%3ATEST%3AENCODE ....