Поскольку все объекты обработки URL-адресов лежат в стандартных библиотеках Какао (NSURL, NSMutableURL, NSMutableURLRequest и т. Д.), Я знаю, что должен упускать из виду простой способ программно составить запрос GET.
В настоящее время я вручную добавляю "?" за которыми следуют пары «имя-значение», соединенные знаком «&», но все мои пары «имя-значение» должны быть закодированы вручную, чтобы NSMutableURLRequest не выходил из строя полностью при попытке подключения к URL-адресу.
Это похоже на то, что я могу использовать предварительно запеченный API для .... есть ли что-нибудь из коробки, чтобы добавить NSDictionary параметров запроса к NSURL? Есть ли другой способ подойти к этому?
objective-c
nsurl
Зев Айзенберг
источник
источник
Ответы:
Представлен в iOS8 и OS X 10.10
NSURLQueryItem
, который можно использовать для построения запросов. Из документов по NSURLQueryItem :Чтобы создать один, используйте назначенный инициализатор,
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;
Я также написал сообщение в блоге о том, как создавать URL-адреса с помощью
NSURLComponents
иNSURLQueryItems
.источник
Для этого вы можете создать категорию
NSDictionary
- в библиотеке Cocoa нет стандартного способа, который я мог бы найти. Код, который я использую, выглядит так:// file "NSDictionary+UrlEncoding.h" #import <cocoa/cocoa.h> @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 .
источник
Я хотел использовать ответ Криса, но он не был написан для автоматического подсчета ссылок (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 & translations [two] = dos & translations [three] = tres
foo = bar & translations [] = uno & translations [] = dos & translations [] = tres
источник
CFURLCreateStringByAddingPercentEscapes
призывы наstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]
Я реорганизовал и преобразовал в ответ ARC от AlBeebe
- (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); }
источник
[NSString stringWithFormat:@"?%@",[pairs componentsJoinedByString:@"&"]];
CFURLCreateStringByAddingPercentEscapes
звонкиstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]
Если вы уже используете AFNetworking (как в случае со мной), вы можете использовать его класс
AFHTTPRequestSerializer
для создания необходимыхNSURLRequest
.[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:@"YOUR_URL" parameters:@{PARAMS} error:nil];
Если вам нужен только URL для вашей работы, используйте
NSURLRequest.URL
.источник
Вот простой пример на 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 }
источник
queryItems
доступны с iOS8.0.Я воспользовался рекомендацией Джоэла
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: $0, value: $1) } guard let url = components.url else { return nil } // Kinda redundant, but we need to call init. self.init(string: url.absoluteString) } }
(
self.init
Метод дрянный, ноNSURL
инициализации с компонентами не было)Может использоваться как
URL(string: "http://www.google.com/", parameters: ["q" : "search me"])
источник
У меня есть другое решение:
http://splinter.com.au/build-a-url-query-string-in-obj-c-from-a-dict
+(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; }
Затем вы можете использовать его так:
NSDictionary *params = @{@"username":@"jim", @"password":@"abc123"}; NSString *urlWithQuerystring = [self addQueryStringToUrl:@"https://myapp.com/login" params:params];
источник
-(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; }
источник
Еще одно решение, если вы используете RestKit есть функция
RKURLEncodedSerialization
называется ,RKURLEncodedStringFromDictionaryWithEncoding
что делает именно то , что вы хотите.источник
Простой способ преобразования NSDictionary в строку запроса url в Objective-c
Пример: first_name = Steve & middle_name = Gates & last_name = Jobs & address = Пало-Альто, Калифорния
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);
Надеюсь поможет :)
источник