दिलचस्प पोस्ट
AsyncTask में संदर्भ प्राप्त हो रहा है जीआईटी का उपयोग करना, मैं एक शाखा में एक फ़ाइल को कैसे अनदेखा कर सकता हूं, लेकिन क्या यह किसी अन्य शाखा में है? एसक्यूएल के जरिए टाइप टाइम की एक योग की गणना करें सीआरसी 32 रिवर्सिंग प्रतिभा का उपयोग कर संपत्ति का प्रकार या कक्षा वेब अनुप्रयोग में मैं सभी HttpSession ऑब्जेक्ट की सूची कैसे प्राप्त करूं? मैं git रीसेट कैसे कर सकता हूं – हार्ड हेड ~ 1? क्या jQuery UI Datepicker शनिवार और रविवार (और छुट्टियों) को अक्षम करने के लिए बनाया जा सकता है? यूटीएफ -8 वर्ण एन्कोडिंग लड़ाइयों json_encode () फ़ाइल नाम में एक बृहदान्त्र के साथ विंडोज में एक फ़ाइल कैसे प्राप्त करें? यह कैसे पता चले कि किसने एक विधि बुलाया? एंड्रॉइड पर जीपीएस सिग्नल की ताकत कैसे मापें? सी # 3.0+ में संपत्ति और फ़ील्ड के बीच का अंतर एएसपी.Net फॉर्म को प्रस्तुत डाक डेटा को पढ़ें एक बैश समारोह के लिए पैरामीटर पासिंग

मैं कैसे समाप्त करने के लिए एक एसिंक्रोनस प्रेषित ब्लॉक का इंतज़ार करूँ?

मैं कुछ कोड का परीक्षण कर रहा हूं जो ग्रैंड सेंट्रल डिस्पैच का इस्तेमाल करते हुए एसिंक्रोनस प्रोसेस करता है। परीक्षण कोड इस तरह दिखता है:

[object runSomeLongOperationAndDo:^{ STAssert… }]; 

परीक्षणों को खत्म करने के लिए ऑपरेशन के लिए इंतजार करना होगा। मेरा वर्तमान समाधान इस तरह दिखता है:

 __block BOOL finished = NO; [object runSomeLongOperationAndDo:^{ STAssert… finished = YES; }]; while (!finished); 

जो थोड़ा कच्चा दिखता है, क्या आपको एक बेहतर तरीका पता है? मैं कतार का पर्दाफाश कर सकता हूं और फिर प्रेषण_एसआईएनसी को कॉल करके ब्लॉक कर सकता हूं:

 [object runSomeLongOperationAndDo:^{ STAssert… }]; dispatch_sync(object.queue, ^{}); 

… लेकिन यह object पर बहुत ज्यादा उजागर हो सकता है

Solutions Collecting From Web of "मैं कैसे समाप्त करने के लिए एक एसिंक्रोनस प्रेषित ब्लॉक का इंतज़ार करूँ?"

एक डिस्पैच_सेमपाहर का उपयोग करने की कोशिश कर रहा है यह कुछ इस तरह दिखना चाहिए:

 dispatch_semaphore_t sema = dispatch_semaphore_create(0); [object runSomeLongOperationAndDo:^{ STAssert… dispatch_semaphore_signal(sema); }]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); 

यह सही ढंग से व्यवहार करना चाहिए, भले ही कुछ runSomeLongOperationAndDo: निर्णय लेता है कि ऑपरेशन वास्तव में लंबे समय तक थ्रेडिंग के योग्य नहीं है और इसके बजाय सिंक्रोनस चलाता है।

मैं हाल ही में इस मुद्दे पर आ गया है और NSObject पर निम्नलिखित श्रेणी लिखा है:

 @implementation NSObject (Testing) - (void) performSelector: (SEL) selector withBlockingCallback: (dispatch_block_t) block { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [self performSelector:selector withObject:^{ if (block) block(); dispatch_semaphore_signal(semaphore); }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_release(semaphore); } @end 

इस तरह मैं आसानी से एक सिंक्रोनस परीक्षण में कॉलबैक के साथ अतुल्यकालिक कॉल को चालू कर सकता हूं:

 [testedObject performSelector:@selector(longAsyncOpWithCallback:) withBlockingCallback:^{ STAssert… }]; 

अन्य उत्तरों में व्यापक रूप से कवर की गई सीमाफोर तकनीक के अतिरिक्त, अब हम एक्ससीटेस्ट एक्सपेक्टेशन के माध्यम से एसिंक्रोनस टेस्ट करने के लिए एक्सकटेस्ट में एक्ससीटेस्ट का उपयोग कर सकते हैं। एसिंक्रोनस कोड का परीक्षण करते समय यह सेमाफोर की आवश्यकता को समाप्त करता है। उदाहरण के लिए:

 - (void)testDataTask { XCTestExpectation *expectation = [self expectationWithDescription:@"asynchronous request"]; NSURL *url = [NSURL URLWithString:@"http://www.apple.com"]; NSURLSessionTask *task = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { XCTAssertNil(error, @"dataTaskWithURL error %@", error); if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSInteger statusCode = [(NSHTTPURLResponse *) response statusCode]; XCTAssertEqual(statusCode, 200, @"status code was not 200; was %d", statusCode); } XCTAssert(data, @"data nil"); // do additional tests on the contents of the `data` object here, if you want // when all done, Fulfill the expectation [expectation fulfill]; }]; [task resume]; [self waitForExpectationsWithTimeout:10.0 handler:nil]; } 

भविष्य के पाठकों की खातिर, जब प्रेषण सेमाफोर तकनीक पूरी तरह जरूरी हो तो एक अद्भुत तकनीक है, मुझे यह स्वीकार करना होगा कि मैं बहुत सारे नए डेवलपर्स को देखता हूं, जो अच्छा अतुल्यकालिक प्रोग्रामिंग पैटर्न से अपरिचित है, सैकफार्स को बहुत जल्दी की ओर झुकता है अतुल्यकालिक बनाने के लिए एक सामान्य तंत्र के रूप में दिनचर्या synchronously व्यवहार इससे भी बदतर मैंने देखा है कि उनमें से कई मुख्य कतार से इस सिक्वारे तकनीक का उपयोग करते हैं (और हमें उत्पादन कड़ियों में मुख्य कतार को अवरुद्ध नहीं करना चाहिए)

मुझे पता है कि यह मामला यहाँ नहीं है (जब यह प्रश्न पोस्ट किया गया था, तो XCTestExpectation जैसे कोई अच्छा उपकरण नहीं था; ये भी, इन परीक्षण सूट में, हमें यह सुनिश्चित करना होगा कि जब तक अतुल्यकालिक कॉल नहीं हो जाता तब तक टेस्ट समाप्त नहीं हो)। यह उन दुर्लभ स्थितियों में से एक है जहां मुख्य धागा को अवरुद्ध करने के लिए सिक्वारे की तकनीक आवश्यक हो सकती है।

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

आम तौर पर इन उत्तरों में से किसी का उपयोग न करें, वे अक्सर स्केल नहीं करेंगे (यहां और वहां अपवाद हैं, निश्चित है)

इन दृष्टिकोणों के साथ असंगत है कि जीसीडी का काम कैसे करना है और अंत में या तो समाप्त हो जाएगा और / या नॉनस्टॉप पोलिंग द्वारा बैटरी की मौत हो जाएगी।

दूसरे शब्दों में, अपने कोड को दोबारा व्यवस्थित करें ताकि परिणाम के लिए कोई तुल्यकालिक इंतजार न हो, लेकिन इसके परिणामस्वरूप राज्य के परिवर्तन (जैसे कॉलबैक / प्रतिनिधि प्रोटोकॉल, उपलब्ध होने, दूर जाने, त्रुटियों आदि) के बारे में सूचित किया जा सकता है। (यदि आपको कॉलबैक नरक पसंद नहीं है तो इन्हें ब्लॉक में पुन: परिष्कृत किया जा सकता है।) क्योंकि यह वास्तविक व्यवहार को बाकी एप्लिकेशन में प्रदर्शित करने के बजाय एक झूठी फानेद के पीछे छिपाने के लिए है।

इसके बजाय, NSNotificationCenter का उपयोग करें , अपने क्लास के लिए कॉलबैक के साथ एक कस्टम प्रतिनिधि प्रोटोकॉल को परिभाषित करें। और अगर आपको प्रतिनिधि कॉलबैक के साथ मिलना पसंद नहीं है, तो उन्हें एक ठोस प्रॉक्सी वर्ग में लपेटें जो कस्टम प्रोटोकॉल लागू करता है और गुणों के विभिन्न ब्लॉक को बचाता है। संभवत: सुविधा निर्माणकर्ता भी प्रदान करते हैं।

शुरुआती काम थोड़ा अधिक है, लेकिन यह लंबी दौड़ में भयानक दौड़-स्थिति और बैटरी-हत्या के मतदान की संख्या को कम कर देगा।

(उदाहरण के लिए मत पूछो, क्योंकि यह तुच्छ है और हमें उद्देश्य-सी मूल बातें भी सीखने के लिए समय व्यतीत करना पड़ा।)

यहां एक निफ्टी चाल है जो एक सेमाफोर का उपयोग नहीं करता है:

 dispatch_queue_t serialQ = dispatch_queue_create("serialQ", DISPATCH_QUEUE_SERIAL); dispatch_async(serialQ, ^ { [object doSomething]; }); dispatch_sync(serialQ, ^{ }); 

आप जो भी करते हैं, एक खाली ब्लॉक के साथ dispatch_sync का उपयोग करके एक सिंक्रोनस ब्लॉक पूरा होने तक तुल्यकालिक रूप से एक सीरियल प्रेषण कतार पर प्रतीक्षा करें।

 - (void)performAndWait:(void (^)(dispatch_semaphore_t semaphore))perform; { NSParameterAssert(perform); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); perform(semaphore); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_release(semaphore); } 

उदाहरण उपयोग:

 [self performAndWait:^(dispatch_semaphore_t semaphore) { [self someLongOperationWithSuccess:^{ dispatch_semaphore_signal(semaphore); }]; }]; 

वहाँ भी SenTestingKitAsync है कि आप इस तरह कोड लिखने देता है:

 - (void)testAdditionAsync { [Calculator add:2 to:2 block^(int result) { STAssertEquals(result, 4, nil); STSuccess(); }]; STFailAfter(2.0, @"Timeout"); } 

(विवरण के लिए objc.io लेख देखें।) और Xcode 6 के बाद से XCTest पर एक AsynchronousTesting श्रेणी है जो आपको इस तरह कोड लिखने देता है:

 XCTestExpectation *somethingHappened = [self expectationWithDescription:@"something happened"]; [testedObject doSomethigAsyncWithCompletion:^(BOOL succeeded, NSError *error) { [somethingHappened fulfill]; }]; [self waitForExpectationsWithTimeout:1 handler:NULL]; 

यहां मेरे परीक्षणों में से एक का एक विकल्प है:

 __block BOOL success; NSCondition *completed = NSCondition.new; [completed lock]; STAssertNoThrow([self.client asyncSomethingWithCompletionHandler:^(id value) { success = value != nil; [completed lock]; [completed signal]; [completed unlock]; }], nil); [completed waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; [completed unlock]; STAssertTrue(success, nil); 
 dispatch_semaphore_t sema = dispatch_semaphore_create(0); [object blockToExecute:^{ // ... your code to execute dispatch_semaphore_signal(sema); }]; while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]]; } 

यह मेरे लिए किया था

कभी-कभी, टाइमआउट लूप भी सहायक होते हैं जब तक आप असेंक कॉलबैक विधि से कुछ (हो सकता है BOOL) संकेत प्राप्त होने तक प्रतीक्षा करें, लेकिन क्या होगा अगर कोई प्रतिक्रिया कभी नहीं, और आप उस लूप से बाहर निकलना चाहते हैं? यहाँ नीचे समाधान है, अधिकतर ऊपर उत्तर दिया गया है, लेकिन टाइमआउट के एक अतिरिक्त के साथ।

 #define CONNECTION_TIMEOUT_SECONDS 10.0 #define CONNECTION_CHECK_INTERVAL 1 NSTimer * timer; BOOL timeout; CCSensorRead * sensorRead ; - (void)testSensorReadConnection { [self startTimeoutTimer]; dispatch_semaphore_t sema = dispatch_semaphore_create(0); while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) { /* Either you get some signal from async callback or timeout, whichever occurs first will break the loop */ if (sensorRead.isConnected || timeout) dispatch_semaphore_signal(sema); [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:CONNECTION_CHECK_INTERVAL]]; }; [self stopTimeoutTimer]; if (timeout) NSLog(@"No Sensor device found in %f seconds", CONNECTION_TIMEOUT_SECONDS); } -(void) startTimeoutTimer { timeout = NO; [timer invalidate]; timer = [NSTimer timerWithTimeInterval:CONNECTION_TIMEOUT_SECONDS target:self selector:@selector(connectionTimeout) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; } -(void) stopTimeoutTimer { [timer invalidate]; timer = nil; } -(void) connectionTimeout { timeout = YES; [self stopTimeoutTimer]; }