ObjectiveC में NSDictionary वस्तुओं से URL क्वेरी पैरामीटर बनाना


90

मानक कोको पुस्तकालयों (NSURL, NSMutableURL, NSMutableURLRequest, आदि) में चारों ओर पड़े हुए सभी URL-हैंडलिंग ऑब्जेक्ट्स के साथ, मुझे पता है कि मुझे GET अनुरोध का प्रोग्राम करने का एक आसान तरीका दिखाई देना चाहिए।

वर्तमान में मैं मैन्युअल रूप से "?" इसके बाद नाम मान जोड़े "और" से जुड़ गए, लेकिन मेरे सभी नाम और मूल्य जोड़े मैन्युअल रूप से एन्कोड किए जाने की आवश्यकता है ताकि NSMutableURLRequest पूरी तरह से विफल न हो जब यह URL से कनेक्ट करने का प्रयास करता है।

ऐसा लगता है कि कुछ के लिए मुझे एक पूर्व-बेक्ड एपीआई का उपयोग करने में सक्षम होना चाहिए .... क्या एनएसयूआरएल को क्वेरी मापदंडों के एक एनएसडीआर को संलग्न करने के लिए बॉक्स से बाहर कुछ है? वहाँ एक और तरीका है मैं इस दृष्टिकोण चाहिए?


इतने जवाब! सवाल और जवाब पर इतने वोट! और अभी भी इसका जवाब नहीं चिह्नित किया गया है। ओह!
बैंगपरेटर

जवाबों:


132

IOS8 और OS X 10.10 में पेश किया गया है NSURLQueryItem, जिसका उपयोग प्रश्नों के निर्माण के लिए किया जा सकता है। NSURLQueryItem पर डॉक्स से :

एक URL के क्वेरी भाग में एक आइटम के लिए एक NSURLQueryItem ऑब्जेक्ट एकल नाम / मूल्य जोड़ी का प्रतिनिधित्व करता है। आप किसी NSURLCompords ऑब्जेक्ट की क्वेरी के साथ क्वेरी आइटम का उपयोग करते हैं।

एक उपयोग करने के लिए निर्दिष्ट प्रारंभ करनेवाला का उपयोग करें 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;

मैं भी एक लिखा है ब्लॉग पोस्ट कैसे साथ यूआरएल का निर्माण करने पर NSURLComponentsऔर NSURLQueryItems


2
क्या होगा अगर डिक्शनरी नेस्टेड है?
हरिस्जमन

1
@hariszaman यदि आप URL के माध्यम से एक नेस्टेड डिक्शनरी भेज रहे हैं तो आपको संभवतः इसके बजाय POST बॉडी के माध्यम से भेजने के बारे में सोचना चाहिए।
जो मैसीलोटी

2
केवल नोट करने के लिए, मान केवल NSString प्रकार का हो सकता है
igrrik

बस यहां एक बिंदु पर जोर देना चाहते हैं: एक NSURLQueryItem के लिए मान केवल एक स्ट्रिंग हो सकता है। ऐसा न होने पर दुर्घटना हो सकती है!
पुलकित शर्मा

47

आप ऐसा करने के लिए एक श्रेणी बना सकते हैं NSDictionary- कोको पुस्तकालय में एक मानक तरीका नहीं है जो मुझे मिल सकता है। मेरे द्वारा उपयोग किया जाने वाला कोड इस तरह दिखता है:

// 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-nsdEDIA.html पर विस्तार से चर्चा करता हूं ।


16
मुझे नहीं लगता कि यह काम करता है। विशेष रूप से, आप stringByAddingPercentEscapesUsingEncoding का उपयोग कर रहे हैं, जो एम्परसेंड्स के साथ-साथ अन्य वर्णों से भी नहीं बचता है जिन्हें RFC 3986 में निर्दिष्ट पैरामीटर में क्वेरी से बचना चाहिए । इसके बजाय Google टूलबॉक्स फॉर मैक एस्केप कोड को देखने पर विचार करें ।
डेव पेक

यह उचित भागने के लिए काम करता है: stackoverflow.com/questions/9187316/…
जोकॉर्टोपस्सी

30

मैं क्रिस के उत्तर का उपयोग करना चाहता था, लेकिन यह स्वचालित संदर्भ गणना (एआरसी) के लिए नहीं लिखा गया था इसलिए मैंने इसे अपडेट किया। मुझे लगा कि मैं अपना समाधान किसी अन्य समस्या के मामले में डालूंगा। नोट: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;
}

मुझे यह कोड पसंद है, केवल जोड़ने के लिए एन्कोडिंग के लिए सभी कुंजी / मूल्यों के लिए यूआरएल सुरक्षित होना चाहिए।
पेलेट

22

यदि मान स्ट्रिंग हैं, तो अन्य उत्तर बहुत बढ़िया काम करते हैं, हालाँकि यदि मान शब्दकोश या सरणियाँ हैं तो यह कोड इसे संभाल लेगा।

यह नोट करना महत्वपूर्ण है कि क्वेरी स्ट्रिंग के माध्यम से किसी सरणी / शब्दकोश को पारित करने का कोई मानक तरीका नहीं है, लेकिन 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 = पट्टी और अनुवाद [एक] = uno और अनुवाद [दो] = डॉस और अनुवाद [तीन] = ट्रेस

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

foo = पट्टी और अनुवाद [] = uno और अनुवाद [] = डॉस और अनुवाद [] = ट्रेस


1
अंतिम 'और' मामले के लिए, मैंने वर्णन के लिए एक कॉल जोड़ा ताकि यह NSNumbers के लिए एक कॉल को लंबाई पर बारफिंग करने के बजाय तार प्रदान करे: '(CFStringRef) [[params objectForKey: key " विवरण : ' धन्यवाद!
JohnQ

बहुत बढ़िया जवाब। लेकिन अगर आप बदलना चाहिए CFURLCreateStringByAddingPercentEscapesके साथ कॉलstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]
S1LENT योद्धा

8

मैंने अलबीबे द्वारा एआरसी के उत्तर को वापस ले लिया और परिवर्तित कर दिया

- (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);
}

2
इसने मेरे लिए बहुत अच्छा काम किया, लेकिन मैंने एक को शामिल करने के लिए अंतिम पंक्ति को बदल दिया? पहले परम से पहले:[NSString stringWithFormat:@"?%@",[pairs componentsJoinedByString:@"&"]];
BFar

1
मुझे लगता है कि आपको CFURLCreateStringByAddingPercentEscapesकॉल को बदलना चाहिएstringByAddingPercentEncodingWithAllowedCharacters:[NSCharac‌​terSet URLQueryAllowedCharacterSet]
S1LENT WARRIOR

5

यदि आप पहले से ही AFNetworking का उपयोग कर रहे हैं (जैसा कि मेरे साथ हुआ था), आप AFHTTPRequestSerializerआवश्यक बनाने के लिए इसका उपयोग कर सकते हैं NSURLRequest

[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:@"YOUR_URL" parameters:@{PARAMS} error:nil];

मामले में आपको केवल अपने काम के लिए URL की आवश्यकता होती है, उपयोग करें NSURLRequest.URL


3

यहाँ स्विफ्ट (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
}

1
बहुत साफ, लेकिन queryItemsiOS8.0 से उपलब्ध हैं।
आदिल सूमरो

धन्यवाद, इसे स्पष्ट करने के लिए एक टिप्पणी जोड़ी।
जोरावर जूल

3

मैंने जोएल की सिफारिश का उपयोग किया URLQueryItems और स्विफ्ट एक्सटेंशन (स्विफ्ट 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"])

2

मुझे एक और उपाय मिला है:

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];

4
कृपया अपने उत्तर में प्रासंगिक कोड पोस्ट करें, वह लिंक हमेशा के लिए आसपास नहीं हो सकता है।
मैडब्रेक्स

2
-(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;
}

यह विशेष वर्णों को नामों या मूल्यों (अंतरिक्ष के अलावा) में ठीक से एनकोड नहीं करता है।
जर्कोन

मुझे विश्वास नहीं है कि अंतरिक्ष को + 20% द्वारा प्रतिस्थापित किया जाना चाहिए, लेकिन यह एकमात्र चरित्र बदल गया है
Przemysław Wrzesi'ski

1

फिर भी एक और उपाय, यदि आप RestKit का उपयोग करते हैं, तो इसमें एक फ़ंक्शन होता है RKURLEncodedSerializationजिसे RKURLEncodedStringFromDictionaryWithEncodingवास्तव में आप चाहते हैं।


1

ऑब्जेक्टिव-सी में NS स्ट्रिंग को url स्ट्रिंग में बदलने का सरल तरीका

Ex: first_name = Steve & Middle_name = Gates & last_name = नौकरियां और पता = Palo Alto, California

    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);

आशा है कि मदद करेगा :)


यह गलत है क्योंकि यह "और" जैसे वर्णों से बच नहीं सकता है यदि वे शब्दकोश मानों में दिखाई देंगे।
थॉमस टेम्पेलमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.