2012-10-27 13 views
26

पर एक पूर्णता हैंडलर को कॉल करना मैंने कुछ संबंधित प्रश्न देखे हैं लेकिन कोई भी इस मामले का उत्तर देने के लिए प्रतीत नहीं होता है। मैं एक ऐसी विधि लिखना चाहता हूं जो पृष्ठभूमि में कुछ काम करेगी। मुझे मूल विधि कॉल के लिए उपयोग किए गए समान थ्रेड/कतार पर पूर्णता कॉलबैक कॉल करने के लिए इस विधि की आवश्यकता है।dispatch_async और मूल कतार

- (void)someMethod:(void (^)(BOOL result))completionHandler { 
    dispatch_queue_t current_queue = // ??? 

    // some setup code here 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     BOOL ok = // some result 

     // do some long running processing here 

     dispatch_async(current_queue, ^{ 
      completionHandler(ok); 
     }); 
    }); 

क्या जादू जादू यहाँ की जरूरत है ताकि पूरा होने हैंडलर एक ही कतार या sameMethod करने के लिए कॉल के रूप में धागे पर कहा जाता है? मैं मुख्य धागा मानना ​​नहीं चाहता। और निश्चित रूप से dispatch_get_current_queue का उपयोग नहीं किया जाना चाहिए।

+0

आप वर्णन कर सकते आप क्या हासिल करने की कोशिश कर रहे हैं? यह आपके विशेष उद्देश्यों के लिए क्यों मायने रखता है कि यह किस धागे पर निष्पादित किया गया है? –

+0

@ क्रिस्टोफर पिक्सले 'कुछ विधि' कुछ पृष्ठभूमि धागे में बुलाया जा सकता है। मुझे ऐसा करना है कि समापन ब्लॉक को उसी धागे पर बुलाया जाता है, न कि मुख्य धागा या कुछ अन्य मनमाने ढंग से पृष्ठभूमि धागा। – rmaddy

+0

मैं इसे समझता हूं। सवाल यह है कि क्यों। क्या कोई तकनीकी कारण है जिसे इसे किसी विशिष्ट धागे पर बुलाया जाना चाहिए? मैं बस सोच रहा हूं कि एक अलग डिज़ाइन हो सकता है जो मदद करेगा। –

उत्तर

4

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

Mike Ash's Block Additions से अनुकूल:

// The last public superclass of Blocks is NSObject 
@implementation NSObject (rmaddy_CompletionHandler) 

- (void)rmaddy_callBlockWithBOOL: (NSNumber *)b 
{ 
    BOOL ok = [b boolValue]; 
    void (^completionHandler)(BOOL result) = (id)self; 
    completionHandler(ok); 
} 

@end 

- (void)someMethod:(void (^)(BOOL result))completionHandler { 
    NSThread * origThread = [NSThread currentThread]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     BOOL ok = // some result 

     // do some long running processing here 

     // Check that there was not a nil handler passed. 
     if(completionHandler){ 
      // This assumes ARC. If no ARC, copy and autorelease the Block. 
      [completionHandler performSelector:@selector(rmaddy_callBlockWithBOOL:) 
             onThread:origThread 
            withObject:@(ok) // or [NSNumber numberWithBool:ok] 
           waitUntilDone:NO]; 
     } 
     }); 
    }); 

यद्यपि आप dispatch_async() उपयोग नहीं कर रहे, इस वजह से यह मूल भेजा कार्य के भीतर निहित वह अभी भी आपकी कार्यक्रम के बाकी के संबंध में अतुल्यकालिक है, ब्लॉक, और waitUntilDone:NO भी इसके संबंध में असीमित बनाता है।

+0

यह एक दिलचस्प विचार है। लेकिन यह एक गंभीर नकारात्मक है। प्रत्येक संभावित ब्लॉक हस्ताक्षर के लिए मैं इस तरीके से उपयोग करना चाहूंगा, मुझे एक संबंधित श्रेणी विधि जोड़नी होगी। – rmaddy

+0

** "मुख्य कतार से अलग, उनमें से कोई भी किसी भी विशेष धागे पर चलने की गारंटी नहीं है" ** - क्या आप मुझे ऐप्पल दस्तावेज़ों में जगह पर इंगित कर सकते हैं जो यह कहता है? – Macondo2Seattle

+0

@ ब्लैकराइडर: "डिस्पैच के लिए क्विकिंग कार्य" शीर्षक के अंतर्गत https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html। –

11

यदि आप ऐप्पल दस्तावेज़ों को देखते हैं, तो दो पैटर्न दिखाई देते हैं।

यदि यह माना जाता है कि पूरा थ्रेड पर पूरा करने वाला हैंडलर चलाना है, तो कोई कतार प्रदान करने की आवश्यकता नहीं है।

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion 

अन्यथा, एपीआई आमतौर पर फोन करने वाले पूछता है एक कतार प्रदान करने के लिए:

[foo doSomethingWithCompletion:completion targetQueue:yourQueue]; 

मेरे सुझाव इस पैटर्न का पालन करने के लिए है एक उदाहरण UIView के animations तरीकों होगा। यदि यह स्पष्ट नहीं है कि पूरा कतार पूरा करने वाले हैंडलर को बुलाया जाना चाहिए, तो कॉलर को इसे पैरामीटर के रूप में स्पष्ट रूप से आपूर्ति करनी चाहिए।

+0

'UIDocument saveToURL के लिए दस्तावेज़ देखें: forSaveOperation: completHandler:'। समापन हैंडलर राज्य का विवरण * यह ब्लॉक कॉलिंग कतार पर लगाया गया है। *। यही वह है जिसे मैं हासिल करना चाहता हूं। – rmaddy

+0

+1 अपनी खुद की सीरियल कतार बनाएं और उस कतार पर विधि और समापन ब्लॉक चलाएं। – Abizern

+0

मैं तर्क दूंगा कि यह यूआईडी दस्तावेज़ में एक बग है। यह मानना ​​नहीं चाहिए कि मूल कतार में वह व्यवहार है जो वह चाहता है। –

2

यकीन नहीं करता है, तो इस समस्या का समाधान होगा, लेकिन के बारे में कैसे ?: GCD के बजाय NSOperations का उपयोग कर

- (void)someMethod:(void (^)(BOOL result))completionHandler { 
NSOperationQueue *current_queue = [NSOperationQueue currentQueue]; 

// some setup code here 
NSOperationQueue *q = [[NSOperationQueue alloc] init]; 
[q addOperationWithBlock:^{ 
    BOOL ok = YES;// some result 

    // do some long running processing here 
    [current_queue addOperationWithBlock:^{ 
     completionHandler(ok); 
    }]; 
}]; 
+1

[NSOperationQueue currentQueue] शून्य वापस आ सकता है। "इस विधि को चल रहे ऑपरेशन के संदर्भ से बाहर कॉल करना आम तौर पर वापस लौटने के परिणामस्वरूप होता है।" – BB9z

0

मैं @rmaddy उल्लेख के रूप में एक पूरा होने के ब्लॉक कुछ कतार पर कुछ कार्य करने के लिए और फिर निष्पादित करने के लिए चाहता था। मैं एप्पल से संगामिति प्रोग्रामिंग गाइड में आए और कार्यान्वित इस (dispatch_retain & के साथ बाहर टिप्पणी की dispatch_released क्योंकि मैं एआरसी का उपयोग कर रहा) - https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1

void average_async(int *data, size_t len, dispatch_queue_t queue, void (^block)(int)) 
{ 
// Retain the queue provided by the user to make 
// sure it does not disappear before the completion 
// block can be called. 
//dispatch_retain(queue); // comment out if use ARC 

// Do the work on user-provided queue 
dispatch_async(queue, ^{ 
    int avg = average(data, len); 
    dispatch_async(queue, ^{ block(avg);}); 

    // Release the user-provided queue when done 
    //dispatch_release(queue); // comment out if use ARC 
}); 
} 
+0

आपने गलत तरीके से जवाब उद्धृत किया :) पहला एसिंक वैश्विक कतार लॉल पर है। उस कतार पर काम करने के बाद ब्लॉक को पारित कतार पर निष्पादित किया जाता है – hariszaman

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^