Ponieważ wszystkie obiekty obsługujące adresy URL znajdują się w standardowych bibliotekach Cocoa (NSURL, NSMutableURL, NSMutableURLRequest itp.), Wiem, że muszę przeoczyć łatwy sposób programistycznego tworzenia żądania GET.
Obecnie ręcznie dołączam „?” po którym następują pary nazwa-wartość połączone znakiem „&”, ale wszystkie moje pary nazwa i wartość muszą być zakodowane ręcznie, aby NSMutableURLRequest nie zakończyło się niepowodzeniem podczas próby połączenia się z adresem URL.
Wydaje mi się, że powinienem być w stanie użyć wstępnie upieczonego interfejsu API do… czy jest coś nieskomplikowanego, aby dołączyć NSDictionary parametrów zapytania do NSURL? Czy jest inny sposób, w jaki powinienem do tego podejść?
objective-c
nsurl
Zev Eisenberg
źródło
źródło
Odpowiedzi:
Wprowadzony w iOS8 i OS X 10.10 jest
NSURLQueryItem
, który może służyć do budowania zapytań. Z dokumentacji w NSURLQueryItem :Aby go utworzyć, użyj wyznaczonego inicjatora,
queryItemWithName:value:
a następnie dodaj je do,NSURLComponents
aby wygenerować plikNSURL
. Na przykład: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
Zwróć uwagę, że znak zapytania i ampersand są obsługiwane automatycznie. Tworzenie
NSURL
ze słownika parametrów jest tak proste, jak: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;
Napisałem również post na blogu o tym, jak tworzyć adresy URL za pomocą
NSURLComponents
iNSURLQueryItems
.źródło
Możesz utworzyć kategorię, aby
NSDictionary
to zrobić - w bibliotece Cocoa nie ma standardowego sposobu, który mógłbym znaleźć. Kod, którego używam, wygląda następująco:// file "NSDictionary+UrlEncoding.h" #import <cocoa/cocoa.h> @interface NSDictionary (UrlEncoding) -(NSString*) urlEncodedString; @end
przy tej implementacji:
// 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
Myślę, że kod jest dość prosty, ale omówię go bardziej szczegółowo pod adresem http://blog.ablepear.com/2008/12/urlencoding-category-for-nsdictionary.html .
źródło
Chciałem użyć odpowiedzi Chrisa, ale nie została napisana dla automatycznego liczenia referencji (ARC), więc zaktualizowałem ją. Pomyślałem, że wkleię moje rozwiązanie na wypadek, gdyby ktoś inny miał ten sam problem. Uwaga:
self
w razie potrzeby zastąp nazwą instancji lub klasy.+(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; }
źródło
Pozostałe odpowiedzi działają świetnie, jeśli wartości są łańcuchami, jednak jeśli wartości są słownikami lub tablicami, ten kod poradzi sobie z tym.
Należy zauważyć, że nie ma standardowego sposobu przekazywania tablicy / słownika przez ciąg zapytania, ale PHP obsługuje to wyjście dobrze
-(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:@"&"]; }
Przykłady
foo = bar i tłumaczenia [jeden] = brak i tłumaczenia [dwa] = polecenia i tłumaczenia [trzy] = tres
foo = bar i tłumaczenia [] = uno i tłumaczenia [] = dos & tłumaczenia [] = tres
źródło
CFURLCreateStringByAddingPercentEscapes
połączenia nastringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]
Refaktoryzowałem i przekonwertowałem na odpowiedź ARC autorstwa 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); }
źródło
[NSString stringWithFormat:@"?%@",[pairs componentsJoinedByString:@"&"]];
CFURLCreateStringByAddingPercentEscapes
połączeniastringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]
Jeśli korzystasz już z AFNetworking (tak jak w przypadku mnie), możesz użyć jego klasy
AFHTTPRequestSerializer
do utworzenia wymaganego plikuNSURLRequest
.[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:@"YOUR_URL" parameters:@{PARAMS} error:nil];
Jeśli potrzebujesz tylko adresu URL do swojej pracy, użyj
NSURLRequest.URL
.źródło
Oto prosty przykład w 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 }
źródło
queryItems
fajne , ale są dostępne od iOS8.0.Przyjąłem zalecenie Joela
URLQueryItems
i zmieniłem go w Swift Extension (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
Metoda jest trochę tandetna, ale nie byłoNSURL
inicjalizacji z komponentami)Może być używany jako
URL(string: "http://www.google.com/", parameters: ["q" : "search me"])
źródło
Mam inne rozwiązanie:
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; }
Następnie możesz go użyć w następujący sposób:
NSDictionary *params = @{@"username":@"jim", @"password":@"abc123"}; NSString *urlWithQuerystring = [self addQueryStringToUrl:@"https://myapp.com/login" params:params];
źródło
-(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; }
źródło
Jeszcze inne rozwiązanie, jeśli używasz RestKit, istnieje funkcja o
RKURLEncodedSerialization
nazwie,RKURLEncodedStringFromDictionaryWithEncoding
która robi dokładnie to, co chcesz.źródło
Prosty sposób konwersji NSDictionary na ciąg zapytania url w Objective-c
Np .: first_name = Steve & middle_name = Gates & last_name = Praca i adres = Palo Alto, Kalifornia
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);
Nadzieja pomoże :)
źródło