16

सीखना मैं ब्लॉक का बड़ा प्रशंसक हूं, लेकिन इन्हें समवर्तीता के लिए उपयोग नहीं किया है। कुछ googling के बाद, मैं एक ही जगह में सीखा सब कुछ छिपाने के लिए इस विचार को एक साथ मिलाया। लक्ष्य पृष्ठभूमि में एक ब्लॉक निष्पादित करने के लिए है, और इसके समाप्त होने पर, (UIView एनीमेशन की तरह) एक और ब्लॉक पर अमल ...एनएसब्लॉकऑपरेशन

- (NSOperation *)executeBlock:(void (^)(void))block completion:(void (^)(BOOL finished))completion { 

    NSOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block]; 

    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ 
     completion(blockOperation.isFinished); 
    }]; 

    [completionOperation addDependency:blockOperation]; 
    [[NSOperationQueue mainQueue] addOperation:completionOperation];  

    NSOperationQueue *backgroundOperationQueue = [[NSOperationQueue alloc] init]; 
    [backgroundOperationQueue addOperation:blockOperation]; 

    return blockOperation; 
} 

- (void)testIt { 

    NSMutableString *string = [NSMutableString stringWithString:@"tea"]; 
    NSString *otherString = @"for"; 

    NSOperation *operation = [self executeBlock:^{ 
     NSString *yetAnother = @"two"; 
     [string appendFormat:@" %@ %@", otherString, yetAnother]; 
    } completion:^(BOOL finished) { 
     // this logs "tea for two" 
     NSLog(@"%@", string); 
    }]; 

    NSLog(@"keep this operation so we can cancel it: %@", operation); 
} 

मेरे प्रश्न हैं:

  1. यह काम करता है जब मैं इसे चलाने , लेकिन क्या मुझे कुछ याद आ रहा है ... छुपे हुए भूमि की खान? मैंने रद्दीकरण का परीक्षण नहीं किया है (क्योंकि मैंने लंबे ऑपरेशन का आविष्कार नहीं किया है), लेकिन क्या ऐसा लगता है कि यह काम करेगा?
  2. मुझे चिंता है कि मुझे पृष्ठभूमि की घोषणा की मेरी योग्यता अर्हता प्राप्त करने की आवश्यकता है ताकि मैं इसे पूर्णता ब्लॉक में देख सकूं। कंपाइलर शिकायत नहीं करता है, लेकिन वहाँ एक छिद्र चक्र वहाँ छिप रहा है?
  3. यदि "स्ट्रिंग" एक ivar था, तो क्या होगा यदि ब्लॉक चल रहा था, तो मैंने महत्वपूर्ण मूल्य देखा? या मुख्य धागे पर टाइमर सेट करें और समय-समय पर लॉग इन करें? क्या मैं प्रगति देख पाऊंगा? क्या मैं इसे परमाणु घोषित करूंगा?
  4. यदि यह मेरी अपेक्षा के अनुसार काम करता है, तो यह सभी विवरण छिपाने और समेकन प्राप्त करने का एक अच्छा तरीका प्रतीत होता है। ऐप्पल ने मेरे लिए यह क्यों नहीं लिखा? क्या मुझे कुछ महत्वपूर्ण याद आ रही है?

धन्यवाद।

+1

आप GCD का उपयोग कर विचार किया है पढ़ने के बाद लगता है? या यह पूरी तरह से एक सीखने का अभ्यास है? एक धारावाहिक कतार ठीक वैसे ही लगता है जो आप खोज रहे हैं। – borrrden

उत्तर

17

मैं NSOperation या NSOperationQueues में एक विशेषज्ञ नहीं हूँ, लेकिन मुझे लगता है कि नीचे कोड हालांकि मुझे लगता है कि यह कुछ चेतावनियां अभी भी है थोड़ा बेहतर है। शायद कुछ प्रयोजनों के लिए पर्याप्त है, लेकिन संगामिति के लिए एक सामान्य समाधान नहीं है:

- (NSOperation *)executeBlock:(void (^)(void))block 
         inQueue:(NSOperationQueue *)queue 
        completion:(void (^)(BOOL finished))completion 
{ 
    NSOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block]; 
    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ 
     completion(blockOperation.isFinished); 
    }]; 
    [completionOperation addDependency:blockOperation]; 

    [[NSOperationQueue currentQueue] addOperation:completionOperation]; 
    [queue addOperation:blockOperation]; 
    return blockOperation; 
} 

अब इसका इस्तेमाल कर सकते हैं:

- (void)tryIt 
{ 
    // Create and configure the queue to enqueue your operations 
    backgroundOperationQueue = [[NSOperationQueue alloc] init]; 

    // Prepare needed data to use in the operation 
    NSMutableString *string = [NSMutableString stringWithString:@"tea"]; 
    NSString *otherString = @"for"; 

    // Create and enqueue an operation using the previous method 
    NSOperation *operation = [self executeBlock:^{ 
     NSString *yetAnother = @"two"; 
     [string appendFormat:@" %@ %@", otherString, yetAnother]; 
    } 
    inQueue:backgroundOperationQueue 
    completion:^(BOOL finished) { 
     // this logs "tea for two" 
     NSLog(@"%@", string); 
    }]; 

    // Keep the operation for later uses 
    // Later uses include cancellation ... 
    [operation cancel]; 
} 

कुछ जवाब अपने प्रश्नों के:

  1. निरस्तीकरण। आमतौर पर आप NSOperation subclass ताकि आप self.isCancelled देख सकें और पहले वापस आएं। this thread देखें, यह एक अच्छा उदाहरण है। वर्तमान उदाहरण में आप यह जांच नहीं सकते कि आप उस ब्लॉक से ऑपरेशन रद्द कर रहे हैं, जिसे आप NSBlockOperation बनाने के लिए आपूर्ति कर रहे हैं क्योंकि उस समय अभी तक ऐसा कोई ऑपरेशन नहीं है। NSBlockOperation एस को अवरुद्ध करते समय ब्लॉक को लागू किया जा रहा है लेकिन cumbersome है। NSBlockOperation एस विशिष्ट आसान मामलों के लिए हैं।अगर आपको रद्दीकरण की आवश्यकता है तो आप NSOperation पर बेहतर सबक्लासिंग कर रहे हैं :)

  2. मुझे यहां कोई समस्या नहीं दिखाई दे रही है। हालांकि दो चीजें नोट करें। ए) मैंने वर्तमान कतार में समापन ब्लॉक चलाने के लिए विधि को बदल दिया है b) पैरामीटर के रूप में एक कतार आवश्यक है। के रूप में @Mike वेलर कहा, तो आप बेहतर आपूर्ति करना चाहिए background queue ताकि आप प्रत्येक आपरेशन प्रति एक बनाने के लिए की जरूरत नहीं है और क्या मुझे लगता है कि हां, तो आप stringatomic बनाना चाहिए अपना सामान :)

  3. को चलाने के लिए उपयोग करने के लिए कतार में चुन सकते हैं । एक चीज आपको भूलना नहीं चाहिए कि अगर आप कतार में कई परिचालनों की आपूर्ति करते हैं तो वे उस क्रम में नहीं चल सकते हैं (जरूरी) ताकि आप अपने string में एक बहुत ही अजीब संदेश के साथ समाप्त हो सकें। यदि आपको एक समय में एक ऑपरेशन चलाने की ज़रूरत है तो आप अपने ऑपरेशन को शुरू करने से पहले [backgroundOperation setMaxConcurrentOperationCount:1]; कर सकते हैं। वहाँ docs हालांकि में एक पढ़ने योग्य टिप्पणी है:

    अतिरिक्त ऑपरेशन कतार व्यवहार कोई कार्रवाई कतार उनकी प्राथमिकता और तत्परता के आधार पर पंक्तिबद्ध आपरेशन वस्तुओं निष्पादित करता है। यदि सभी कतारबद्ध ऑपरेशन ऑब्जेक्ट्स की प्राथमिकता समान होती है और कतार में रखे जाने पर निष्पादित करने के लिए तैयार होती है- यानी, उनकी हैरडी विधि YES लौटाती है- उन्हें उस क्रम में निष्पादित किया जाता है जिसमें उन्हें कतार में सबमिट किया गया था। एक कतार के लिए जिनकी अधिकतम संख्या में समवर्ती संचालन 1 पर सेट किया गया है, यह एक धारावाहिक कतार के बराबर है। हालांकि, आपको ऑपरेशन ऑब्जेक्ट्स के धारावाहिक निष्पादन पर कभी भरोसा नहीं करना चाहिए। एक ऑपरेशन की तैयारी में परिवर्तन परिणामस्वरूप निष्पादन आदेश बदल सकते हैं।

  4. मैं इन पंक्तियों को आप जानते :)

+0

उत्कृष्ट उत्तर। बहुत बहुत धन्यवाद। – danh

+0

लेकिन पूरी तरह से सही नहीं, IMHO। निष्पादित करने के लिए कॉलबैक में कतार पैरामीटर – decades

+0

युग बाद में गायब है, मैंने नमूना कोड तय किया है। – nacho4d

8

आपको प्रत्येक executeBlock:completion: कॉल के लिए एक नया NSOperationQueue नहीं बनाना चाहिए। यह महंगा है और इस एपीआई के उपयोगकर्ता पर कोई नियंत्रण नहीं है कि एक समय में कितने ऑपरेशन निष्पादित हो सकते हैं।

यदि आप NSOperation उदाहरण लौट रहे हैं तो आपको कॉलर को इसे छोड़ना चाहिए ताकि यह तय किया जा सके कि कौन सी कतार उन्हें जोड़ना है। लेकिन उस समय, आपकी विधि वास्तव में कुछ भी सहायक नहीं कर रही है और कॉलर भी NSBlockOperation स्वयं बना सकता है।

यदि आप पृष्ठभूमि में एक ब्लॉक को घुमाने के लिए एक आसान और आसान तरीका चाहते हैं और इसे समाप्त होने पर कुछ कोड करना चाहते हैं, तो संभवतः आप dispatch_* फ़ंक्शंस के साथ कुछ सरल जीसीडी कॉल करने से बेहतर हैं। उदाहरण के लिए:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    // do your background work 
    // ... 

    // now execute the 'completion' code. 
    // you often want to dispatch back to the main thread to update the UI 
    // For example: 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     // update UI, etc. 
     myLabel.text = @"Finished"; 
    }); 

}); 
+3

मैं देखता हूं, धन्यवाद। रद्द करने के बारे में कैसे? – danh

+0

@danh, सामग्री को रद्द करने के बारे में कृपया विज्ञापन एनएसओपेरेशंस क्यूयू और विधि 'रद्द करेंऑलऑपरेशंस';) –