표준 Cocoa 라이브러리 (NSURL, NSMutableURL, NSMutableURLRequest 등)에있는 모든 URL 처리 개체를 사용하여 프로그래밍 방식으로 GET 요청을 작성하는 쉬운 방법을 간과해야한다는 것을 알고 있습니다.
현재 수동으로 “?”를 추가하고 있습니다. “&”로 결합 된 이름 값 쌍이 뒤 따르지만 모든 이름 및 값 쌍은 수동으로 인코딩해야 NSMutableURLRequest가 URL에 연결하려고 할 때 완전히 실패하지 않습니다.
이것은 내가 미리 구운 API를 사용할 수 있어야하는 것처럼 느껴집니다 …. NSURL에 쿼리 매개 변수의 NSDictionary를 추가 할 수있는 상자가 있습니까? 이에 접근해야하는 다른 방법이 있습니까?
답변
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;
및 을 사용하여 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 에서 좀 더 자세히 논의합니다 .
답변
Chris의 답변을 사용하고 싶었지만 ARC ( Automatic Reference Counting) 용으로 작성되지 않았 으므로 업데이트했습니다. 다른 사람이 이와 동일한 문제가있는 경우를 대비하여 내 솔루션을 붙여 넣을 것이라고 생각했습니다. 참고 :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
}
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
답변
리팩토링하고 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
.
답변
다음은 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
}