2012-02-23 7 views
7

मुझे अपने सर्वर पर कुछ पोस्ट कॉल करने की ज़रूरत है, लेकिन मुझे मुख्य धागे को अवरुद्ध करने की आवश्यकता नहीं है। जैसा कि मैं समझता हूं, NSMutableURLRequest और NSURLConnection थ्रेड सुरक्षित नहीं हैं, इसलिए NSURLConnection के एसिंक विधि का उपयोग करना सबसे अच्छा है।उद्देश्य-सी: प्रतिनिधि विधि का उपयोग किए बिना Async/पृष्ठभूमि POST?

इस बारे में मेरा सवाल यह है कि, प्रतिनिधि विधि का उपयोग करने के बजाय, मैं इसे विधि में कैसे अच्छी तरह से पैकेज कर सकता हूं? मुझे क्या करना पसंद करेंगे:

NSData *returnedData = [Utility postDataToURL:@"some string of data"]; 

यह कैसे यह आसान निम्न विधि के साथ किया जाता है:

[NSURLConnection sendSynchronousRequest:serviceRequest returningResponse:&serviceResponse error:&serviceError]; 

यह इतना एक विधि के भीतर सब कुछ रखने, तो बस होने अपने डेटा यह से लौटे अच्छा है !

क्या इसके लिए कोई ब्लॉक आधारित विधियां हैं? यह एक मुद्दा बन जाता है जब मुझे लगभग 50 अलग-अलग कॉल के लिए विधियों को लिखने की आवश्यकता होती है और प्रत्येक को एक ही प्रतिनिधि विधि का उपयोग करने की आवश्यकता होती है। क्या मैं इस बारे में गलत तरीके से जा रहा हूं?

यह केवल आईओएस 5 के लिए होना चाहिए।

+1

आप कहते हैं कि आप नहीं चाहते हैं मुख्य धागे को अवरुद्ध करें, लेकिन आपने जो कहा है वह बहुत स्पष्ट रूप से तुल्यकालिक है, यानी यह मुख्य धागे को अवरुद्ध करेगा (या कम से कम, वह धागा जिसे आप इसे बुला रहे हैं)। –

+0

यह एक उदाहरण है कि मैं डेटा को वापस करने में सक्षम होना कितना आसान हूं। –

उत्तर

9

आईओएस 5 sendAsynchronousRequest:queue:completionHandler: जोड़ता है जो मुझे लगता है कि आप क्या चाहते हैं। मुझे उपलब्ध होने पर मेरा कोड सेट अप करने के लिए सेट किया गया है, लेकिन पृष्ठभूमि जीसीडी कतार पर एक सिंक्रोनस फ़ेच करने और परिणाम के साथ मुख्य धागे पर hopping करने पर वापस गिरने के लिए अगर यह नहीं है। उत्तरार्द्ध कम शक्ति कुशल होगा लेकिन यह केवल विरासत समर्थन बनाए रखने के लिए है।

if([NSURLConnection respondsToSelector:@selector(sendAsynchronousRequest:queue:completionHandler:)]) 
{ 
    // we can use the iOS 5 path, so issue the asynchronous request 
    // and then just do whatever we want to do 
    [NSURLConnection sendAsynchronousRequest:request 
     queue:[NSOperationQueue mainQueue] 
     completionHandler: 
     ^(NSURLResponse *response, NSData *data, NSError *error) 
     { 
      [self didLoadData:data]; 
     }]; 
} 
else 
{ 
    // fine, we'll have to do a power inefficient iOS 4 implementation; 
    // hop onto the global dispatch queue... 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
    ^{ 
     // ... perform a blocking, synchronous URL retrieval ... 
     NSError *error = nil; 
     NSURLResponse *urlResponse = nil; 
     NSData *responseData = 
      [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error]; 

     // ... and hop back onto the main queue to handle the result 
     dispatch_async(dispatch_get_main_queue(), 
     ^{ 
      [self didLoadData:responseData]; 
     }); 
    }); 
} 

उत्पादन कोड में आप वास्तव में जाँच होगी error और HTTP प्रतिक्रिया कोड, स्पष्ट रूप से (एक सर्वर 404 प्रतिक्रिया के रूप में शायद बस के रूप में ज्यादा कनेक्शन विफलता के रूप में अपने दृष्टिकोण से एक त्रुटि है)।

BetterNSURLConnection:

+0

मैं आईओएस 5 ऐप बना रहा हूं इसलिए यह पूरी तरह से काम करता है! धन्यवाद! –

+0

क्या नाम के साथ अपने स्वयं के उपयोग के बजाय कतार को [NSOperationQueue mainQueue] पर सेट करना सबसे अच्छा है? –

+0

यह वास्तव में आप पर निर्भर है। मैंने 'mainQueue' का उपयोग किया क्योंकि मैं पूरा करने वाले हैंडलर में कुछ UIKit सामान करता हूं - जिस कतार को आप पहचान रहे हैं वह वह जगह है जहां आप पूरा करने वाले हैंडलर बनना चाहते हैं, इसलिए यदि आप पृष्ठभूमि में ऐसा करना चाहते हैं तो अपनी वैकल्पिक कतार में प्रवेश करें। – Tommy

1

iOS 5.0 > आप NSURLConnection Class पर sendAsynchronousRequest विधि का उपयोग कर सकते हैं और यह ब्लॉक का उपयोग करता है। यदि आप iOS 4.0 > का भी समर्थन करना चाहते हैं तो आपको अपने स्वयं के ब्लॉक आधारित असिंक्रोनस यूआरएल लोडिंग को लिखना होगा जो लिखना काफी आसान है। MKNetworkKit का उपयोग करके आप बेहतर हैं।

लेकिन मुझे मुख्य धागे को अवरुद्ध करने की आवश्यकता नहीं है। जैसा कि मैं समझता हूं, NSMutableURLRequest और NSURLConnection थ्रेड सुरक्षित नहीं हैं, इसलिए NSURLConnection की async विधि का उपयोग करना सबसे अच्छा है।

आप सिंक्रोनस नेटवर्क कनेक्शन नहीं करना चाहते हैं, यह थ्रेड को अवरुद्ध करता है जिसे भी इसे बुलाया जाता है (इसके मुख्य धागे भी इससे भी बदतर)। आप मुख्य धागे पर असीमित नेटवर्क कनेक्शन कर सकते हैं। यदि आप गैर-मुख्य धागे पर NSRLConnection को कॉल करना चाहते हैं तो उस थ्रेड पर रनलूप बनाना होगा (यदि आप तब नहीं करते हैं तो NSRLConnection के प्रतिनिधि विधियों को कभी भी कॉल नहीं किया जाता है)।

+1

हालांकि शेष मूल रूप से मेरे उत्तर के समान ही है, मुझे यकीन नहीं है कि मैं अंतिम वाक्य से सहमत हूं; यह कुछ ऐसा है जो आप कोड की लगभग 50 पंक्तियों में 5 या 4 के लिए कार्यान्वित कर सकते हैं ताकि बड़ी तीसरी पार्टी लाइब्रेरी को शामिल न किया जाए, ऐसा लगता है कि यह पोस्टर को बेहतर तरीके से बंद कर देगा, विशेष रूप से समर्थन और परीक्षण विधियों को दिया जाएगा। – Tommy

+0

@Tommy इस विशिष्ट कार्य के लिए, मैं सहमत हूं कि आपको किसी तृतीय पक्ष लाइब्रेरी की आवश्यकता नहीं है। यदि आप आरईएसटी पैरामीटर, इमेज कैशिंग इत्यादि को संभालने के लिए आसान तरीका जैसे यूटिलिटी क्लास में और अधिक सुविधाएं जोड़ना चाहते हैं तो इसका उपयोग करने की सिफारिश की जा रही है, हालांकि आप अपनी आवश्यकताओं के आधार पर सुविधाओं को जोड़ सकते हैं, आपका डिज़ाइन जटिल हो सकता है और ये तीसरे पक्ष के ढांचे आसान काम आता है। – 0x8badf00d

0

मैं एक आंतरिक कार्यकर्ता को खोलने के लिए एक मुखौटा विधि का उपयोग करता हूं जो सिंक्रोनस कॉल को जारी करता है। जिस दर पर आप कॉल भेजते हैं उसके आधार पर, यह काम कर सकता है। उदाहरण:

// Presented in @interface 
-(void)sendPostRequest { 
    // Last chance to update main thread/UI 
    NSInvocationOperation *op = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(sendPostRequest_internal) object:nil] autorelease]; 
    [opQueue addOperation:op]; 
} 

// Hidden in @implementation 
-(void)sendPostRequest_internal { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSURLRequest *request = // yadda, you might use NSURLMutableRequest 
    NSURLResponse *response = nil; 
    NSError *error = nil; 
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:response error:error]; 

    // process data, retain things as needed, post results using performSelectorOnMainThread: 

    [pool release]; 
} 

यह मेरी प्रयोजनों के लिए बहुत अच्छी तरह से काम करता है, लेकिन आप async सामान, जो वास्तव में बहुत बुरा नहीं है करने के लिए एक छोटे से गहरा गड्ढा करने की आवश्यकता हो सकती है।

1

मैं इस समस्या को पूर्व 5.0-तो मैं NSURLConnection प्रतिनिधि प्रोटोकॉल संभाल और कॉल करने वालों को बंद के साथ एक इंटरफेस की पेशकश करने के एक छोटे से वर्ग बनाया था।ज

@property (retain, nonatomic) NSURLRequest *request; 

BetterNSURLConnection.m

@property (retain, nonatomic) NSURLConnection *connection; 
@property (retain, nonatomic) NSHTTPURLResponse *response; 
@property (retain, nonatomic) NSMutableData *responseData; 

@property (copy, nonatomic) void (^completionBlock)(id, NSHTTPURLResponse *); 
@property (copy, nonatomic) void (^errorBlock)(NSError *); 

... आप उन ब्लॉक हस्ताक्षर खूबसूरत बनाने के लिए ... तो typedefs जोड़ सकते हैं:

@synthesize connection = _connection; 
@synthesize response = _response; 
@synthesize responseData = _responseData; 
@synthesize completionBlock = _completionBlock; 
@synthesize errorBlock = _errorBlock; 
@synthesize request=_request; 


- (void)startWithCompletion:(void (^)(id, NSHTTPURLResponse *))completionBlock error:(void (^)(NSError *))errorBlock { 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 

    self.completionBlock = completionBlock; 
    self.errorBlock = errorBlock; 
    self.responseData = [NSMutableData data]; 

    NSURLConnection *connection = [NSURLConnection connectionWithRequest:self.request delegate:self]; 
    self.connection = connection; 
    [self.connection start]; 
    [connection release]; 
} 

... तो प्रतिनिधि करना इस तरह:

- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSHTTPURLResponse *)response { 

    [self.responseData setLength:0]; 
    self.response = response; 
} 

- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data { 

    [self.responseData appendData:data]; 
} 

- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error { 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
    self.errorBlock(error); 
    self.connection = nil; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection { 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 

    if (self.response.statusCode >= 400) { 
     self.errorBlock(error); 
    } else { 
     // i do json requests, and call a json parser here, but you might want to do something different 
     id result = [self parseResponse:self.responseData]; 
     self.completionBlock(result, self.response); 
    } 
    self.connection = nil; 
} 
संबंधित मुद्दे