दिलचस्प पोस्ट
कैसे जावा में दो पूर्णांक तुलना करने के लिए? c # डेटाटेबल से सीएसवी एक एसएसएच रिमोट कमान कम पर्यावरण चर क्यों मिलता है, जब मैन्युअल रूप से चलाते हैं? एन-वे मर्ज के लिए एल्गोरिदम जावास्क्रिप्ट छिपाना / शो तत्व एंड्रॉइड SQLite डेटाबेस: धीमा प्रविष्टि किसी रिश्तेदार पथ से एक मॉड्यूल आयात करें सी # में ऑडियंस बनाने का एक आसान तरीका है? आप Google प्रोग्राममेटिक जावा एपीआई कैसे खोज सकते हैं मैं कर्सर को कर्सर की तरफ कैसे कर सकता हूं? स्ट्रिंगिफिकेशन – यह कैसे काम करता है? डेटाबेस में विभिन्न संस्थाओं से समान डेटा – सर्वश्रेष्ठ अभ्यास – फ़ोन नंबर उदाहरण jQuery दस्तावेज़.ready बनाम स्वयं कॉल अनाम समारोह जावा फ़ाइल का आकार कुशलतापूर्वक मिलता है MaxHeight और MaxWidth बाधाओं के साथ छवि का आकार बदलें

AFNetworking और पृष्ठभूमि स्थानान्तरण

मैं नया आईओएस 7 NSURLSession पृष्ठभूमि ट्रांसफ़र सुविधाओं और NSURLSession (संस्करण 2 और 3) का लाभ लेने का थोड़ा भ्रम हूँ।

मैंने WWDC 705 - What's New in Foundation Networking सत्र WWDC 705 - What's New in Foundation Networking देखा है, और उन्होंने पृष्ठभूमि डाउनलोड का प्रदर्शन किया जो एप समाप्त हो जाने या क्रैश होने के बाद भी जारी है।

यह नया एपीआई application:handleEventsForBackgroundURLSession:completionHandler: का उपयोग किया जाता है application:handleEventsForBackgroundURLSession:completionHandler: और तथ्य यह है कि सत्र के प्रतिनिधि को अंततः कॉलबैक मिलेंगे और इसके कार्य को पूरा कर सकते हैं

इसलिए मैं सोच रहा हूं कि इसका इस्तेमाल AFNetworking (यदि संभव हो) के साथ करने के लिए पृष्ठभूमि में डाउनलोड जारी रखने के लिए।

समस्या यह है कि, AFNetworking सभी अनुरोध करने के लिए ब्लॉकों आधारित एपीआई का आसानी से उपयोग करता है, लेकिन अगर उन अनुप्रयोगों को समाप्त या क्रैश किया गया ऐप भी चले गए हैं तो मैं काम कैसे पूरा कर सकता हूं?

या शायद मैं यहाँ कुछ याद कर रहा हूँ …

मुझे मेरा आशय समझाने दीजिए:

उदाहरण के लिए मेरा ऐप एक फोटो मैसेजिंग ऐप है, यह कहने के लिए कि मेरे पास एक PhotoMessage ऑब्जेक्ट है जो एक संदेश का प्रतिनिधित्व करती है और इस ऑब्जेक्ट में गुण हैं

  • state – फोटो डाउनलोड की स्थिति का वर्णन।
  • resourcePath पाथ – अंतिम डाउनलोड की गई फोटो फ़ाइल का पथ।

इसलिए जब मुझे सर्वर से नया संदेश मिलता है, तो मैं एक नया PhotoMessage ऑब्जेक्ट PhotoMessage , और उसके फोटो संसाधन को डाउनलोड करना शुरू कर देता PhotoMessage

 PhotoMessage *newPhotoMsg = [[PhotoMessage alloc] initWithInfoFromServer:info]; newPhotoMsg.state = kStateDownloading; self.photoDownloadTask = [[BGSessionManager sharedManager] downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSURL *filePath = // some file url return filePath; } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { if (!error) { // update the PhotoMessage Object newPhotoMsg.state = kStateDownloadFinished; newPhotoMsg.resourcePath = filePath; } }]; [self.photoDownloadTask resume]; 

जैसा कि आप देख सकते हैं, मैं उस प्रतिक्रिया के अनुसार PhotoMessage ऑब्जेक्ट को अपडेट करने के लिए पूरा ब्लॉक का उपयोग करता हूं I

पृष्ठभूमि हस्तांतरण के साथ मैं यह कैसे कर सकता हूं? यह पूरा ब्लॉक कॉल नहीं किया जाएगा और नतीजतन, मैं newPhotoMsg अद्यतन नहीं कर सकता

वेब के समाधान से एकत्रित समाधान "AFNetworking और पृष्ठभूमि स्थानान्तरण"

कुछ विचार:

  1. आपको यह सुनिश्चित करना है कि यूआरएल लोडिंग सिस्टम प्रोग्रामिंग गाइड के हैंडलिंग आईओएस पृष्ठभूमि की गतिविधि अनुभाग में उल्लिखित आवश्यक कोडिंग को कहते हैं:

    अगर आप आईओएस में NSURLSession का प्रयोग कर रहे हैं, तो आपका ऐप स्वचालित रूप से फिर से लॉन्च किया जाता है जब एक डाउनलोड पूरा हो जाता है। आपका ऐप का application:handleEventsForBackgroundURLSession:completionHandler: विधि उचित सत्र को application:handleEventsForBackgroundURLSession:completionHandler: बनाने के लिए जिम्मेदार है, पूर्णता वाले हैंडलर को संचयित करने और उस हैंडलर को कॉल करने के लिए जब सत्र आपके सत्र प्रतिनिधि के URLSessionDidFinishEventsForBackgroundURLSession: सत्र URLSessionDidFinishEventsForBackgroundURLSession: विधि को कॉल करता है।

    यह गाइड आपको बता सकता है कि आप क्या कर सकते हैं। सच कहूँ तो, मुझे लगता है कि फाउंडेशन नेटवर्किंग में WWDC 2013 वीडियो व्हाट्स न्यू के उत्तरार्ध में चर्चा की गई कोड के नमूनों में और भी अधिक स्पष्ट हैं।

  2. AFURLSessionManager मूल कार्यान्वयन पृष्ठभूमि सत्रों के साथ संयोजन के साथ काम करेगा यदि ऐप केवल निलंबित किया गया है (आप अपने ब्लॉकों को जब नेटवर्क कार्य किया जाता है, आपको लगता है कि आपने उपरोक्त काम किया है) देखेंगे। लेकिन जैसा कि आपने अनुमान लगाया है, AFURLSessionManager विधि के पास पारित किए जाने वाले कार्य-विशिष्ट ब्लॉक मानदंड, जहां आप अपलोड और डाउनलोड करने के लिए NSURLSessionTask बनाते हैं, "यदि ऐप निरस्त हो या क्रैश हो।"

    पृष्ठभूमि अपलोड के लिए, यह एक झुंझलाहट है (जैसा कि आपके कार्य-स्तर की सूचनाप्रद प्रगति और पूरा होने वाला पूरा ब्लॉक जिसे कार्य बनाते समय कहा नहीं जाएगा)। लेकिन यदि आप सत्र-स्तरीय प्रस्तुतियों (जैसे setTaskDidCompleteBlock और setTaskDidSendBodyDataBlock ) को setTaskDidSendBodyDataBlock , तो इसे ठीक से कहा जाता है (आप संभालने के दौरान हमेशा इन ब्लॉकों को सेट करते हैं जब आप सत्र प्रबंधक को पुन: इन्स्तांत करते हैं)।

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

  3. एक विकल्प, आप डिफ़ॉल्ट (गैर-पृष्ठभूमि) NSURLSession साथ छड़ी कर सकते हैं, लेकिन यह सुनिश्चित कर लें कि आपका ऐप अनुरोध समाप्त करने के लिए थोड़ी देर के लिए अनुरोध करता है कि उपयोगकर्ता कार्य जारी रखने के दौरान ऐप को छोड़ देता है उदाहरण के लिए, अपने NSURLSessionTask बनाने से पहले, आप एक UIBackgroundTaskIdentifier बना सकते हैं:

     UIBackgroundTaskIdentifier __block taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) { // handle timeout gracefully if you can [[UIApplication sharedApplication] endBackgroundTask:taskId]; taskId = UIBackgroundTaskInvalid; }]; 

    लेकिन सुनिश्चित करें कि नेटवर्क कार्य का पूरा ब्लॉक आईओएस को सही ढंग से सूचित करता है कि यह पूर्ण है:

     if (taskId != UIBackgroundTaskInvalid) { [[UIApplication sharedApplication] endBackgroundTask:taskId]; taskId = UIBackgroundTaskInvalid; } 

    यह एक पृष्ठभूमि NSURLSession रूप में शक्तिशाली नहीं है (उदाहरण के लिए, आपके पास सीमित समय उपलब्ध है), लेकिन कुछ मामलों में यह उपयोगी हो सकता है।


अद्यतन करें:

मैंने सोचा कि मैं AFNetworking से पृष्ठभूमि डाउनलोड करने के तरीके का व्यावहारिक उदाहरण जोड़ूंगा।

  1. सबसे पहले अपने पृष्ठभूमि प्रबंधक को परिभाषित करें।

     // // BackgroundSessionManager.h // // Created by Robert Ryan on 10/11/14. // Copyright (c) 2014 Robert Ryan. All rights reserved. // #import "AFHTTPSessionManager.h" @interface BackgroundSessionManager : AFHTTPSessionManager + (instancetype)sharedManager; @property (nonatomic, copy) void (^savedCompletionHandler)(void); @end 

    तथा

     // // BackgroundSessionManager.m // // Created by Robert Ryan on 10/11/14. // Copyright (c) 2014 Robert Ryan. All rights reserved. // #import "BackgroundSessionManager.h" static NSString * const kBackgroundSessionIdentifier = @"com.domain.backgroundsession"; @implementation BackgroundSessionManager + (instancetype)sharedManager { static id sharedMyManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedMyManager = [[self alloc] init]; }); return sharedMyManager; } - (instancetype)init { NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kBackgroundSessionIdentifier]; self = [super initWithSessionConfiguration:configuration]; if (self) { [self configureDownloadFinished]; // when download done, save file [self configureBackgroundSessionFinished]; // when entire background session done, call completion handler [self configureAuthentication]; // my server uses authentication, so let's handle that; if you don't use authentication challenges, you can remove this } return self; } - (void)configureDownloadFinished { // just save the downloaded file to documents folder using filename from URL [self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) { if ([downloadTask.response isKindOfClass:[NSHTTPURLResponse class]]) { NSInteger statusCode = [(NSHTTPURLResponse *)downloadTask.response statusCode]; if (statusCode != 200) { // handle error here, eg NSLog(@"%@ failed (statusCode = %ld)", [downloadTask.originalRequest.URL lastPathComponent], statusCode); return nil; } } NSString *filename = [downloadTask.originalRequest.URL lastPathComponent]; NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *path = [documentsPath stringByAppendingPathComponent:filename]; return [NSURL fileURLWithPath:path]; }]; [self setTaskDidCompleteBlock:^(NSURLSession *session, NSURLSessionTask *task, NSError *error) { if (error) { // handle error here, eg, NSLog(@"%@: %@", [task.originalRequest.URL lastPathComponent], error); } }]; } - (void)configureBackgroundSessionFinished { typeof(self) __weak weakSelf = self; [self setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession *session) { if (weakSelf.savedCompletionHandler) { weakSelf.savedCompletionHandler(); weakSelf.savedCompletionHandler = nil; } }]; } - (void)configureAuthentication { NSURLCredential *myCredential = [NSURLCredential credentialWithUser:@"userid" password:@"password" persistence:NSURLCredentialPersistenceForSession]; [self setTaskDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *credential) { if (challenge.previousFailureCount == 0) { *credential = myCredential; return NSURLSessionAuthChallengeUseCredential; } else { return NSURLSessionAuthChallengePerformDefaultHandling; } }]; } @end 
  2. सुनिश्चित करें कि ऐप प्रतिनिधि कंटेंट हैंडलर (आवश्यकतानुसार पृष्ठभूमि सत्र को तत्काल) को बचाता है:

     - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler { NSAssert([[BackgroundSessionManager sharedManager].session.configuration.identifier isEqualToString:identifier], @"Identifiers didn't match"); [BackgroundSessionManager sharedManager].savedCompletionHandler = completionHandler; } 
  3. फिर अपने डाउनलोड शुरू करें:

     for (NSString *filename in filenames) { NSURL *url = [baseURL URLByAppendingPathComponent:filename]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [[[BackgroundSessionManager sharedManager] downloadTaskWithRequest:request progress:nil destination:nil completionHandler:nil] resume]; } 

    ध्यान दें, मैं उन कार्यों से संबंधित किसी भी ब्लॉक की आपूर्ति नहीं करता, क्योंकि ये पृष्ठभूमि सत्रों के साथ विश्वसनीय नहीं हैं। (पृष्ठभूमि डाउनलोड ऐप समाप्त होने के बाद भी बढ़ जाती है और ये ब्लॉकों लंबे समय से गायब हो गए हैं।) किसी को सत्र-स्तर पर भरोसा करना चाहिए, आसानी से निर्मित setDownloadTaskDidFinishDownloadingBlock केवल

स्पष्ट रूप से यह एक सरल उदाहरण (केवल एक पृष्ठभूमि सत्र ऑब्जेक्ट है, बस फाइल के नाम के रूप में यूआरएल के अंतिम घटक का इस्तेमाल करते हुए दस्तावेज़ फ़ोल्डर में फ़ाइलों को सहेजना आदि), लेकिन उम्मीद है कि यह पैटर्न को दिखाता है

कॉलबैक ब्लॉक हैं या नहीं, यह किसी भी फर्क नहीं करना चाहिए। जब आप एक AFURLSessionManager को इन्स्तांत करते हैं, तो इसे NSURLSessionConfiguration backgroundSessionConfiguration: साथ इन्स्तांत करना सुनिश्चित करें:। साथ ही, अपने कॉलबैक ब्लॉक के साथ मैनेजर के setDidFinishEventsForBackgroundURLSessionBlock को कॉल करना सुनिश्चित करें – यह वह जगह है जहां आपको आमतौर पर NSURLSessionDelegate की विधि में कोड लिखना चाहिए: URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session । इस कोड को आपके ऐप प्रतिनिधि की पृष्ठभूमि डाउनलोड करने के पूर्ण संचालनकर्ता को शामिल करना चाहिए।

पृष्ठभूमि डाउनलोड कार्यों के बारे में सलाह के एक शब्द – अग्रभूमि में चलते समय भी, उनके समय-समय पर ध्यान नहीं दिया जाता है, जिसका अर्थ है कि आप एक डाउनलोड पर "अटक" कर सकते हैं जो कि जवाब नहीं दे रहा है यह कहीं भी दस्तावेज नहीं है और मुझे कुछ समय के लिए पागल कर दिया। पहला संदिग्ध वायुसेना था लेकिन यहां तक ​​कि एनएसआरएलएसएशन सीधे फोन करने के बाद भी, व्यवहार उसी ही बना रहा।

सौभाग्य!

AFURLSessionManager

AFURLSessionManager एक निर्दिष्ट NSURLSession ऑब्जेक्ट के आधार पर एक NSURLSession ऑब्जेक्ट बनाता है और प्रबंधित करता है, जो <NSURLSessionTaskDelegate> , <NSURLSessionDataDelegate> , <NSURLSessionDownloadDelegate> , और <NSURLSessionDelegate>

यहाँ दस्तावेज़ीकरण के लिए लिंक