11

में तुल्यकालिक बारी मैं एक async एपीआई कि इस तरह दिखना रैप करने के लिए करना चाहते हैं:कैसे एक अतुल्यकालिक विधि है कि एक ब्लॉक लेता लपेट और यह उद्देश्य सी

[someObject completeTaskWithCompletionHandler:^(NSString *result) { 

}]; 

एक तुल्यकालिक विधि में है कि मैं इस

की तरह कॉल कर सकते हैं
NSString *result = [someObject completeTaskSynchronously]; 

मैं यह कैसे कर सकता हूं?

-(NSString *) completeTaskSynchronously { 
    __block NSString *returnResult; 
    self.semaphore = dispatch_semaphore_create(0); 
    [self completeTaskWithCompletionHandler:^(NSString *result) { 
     resultResult = result; 
     dispatch_semaphore_signal(self.semaphore); 
    }]; 

    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); 
    return resultResult; 
} 

लेकिन यह does not काम करने के लिए, यह मूल रूप से सिर्फ dispatch_semaphore_wait पर रोक लग रहे: मैं कुछ दस्तावेज़ पढ़ने और गूगल खोज, और "dispatch_semaphore" का उपयोग करने के लिए क्या करने की कोशिश तो की तरह इसे प्राप्त करने की कोशिश की थी। निष्पादन ब्लॉक के अंदर कभी नहीं पहुंचता है जो _signal करता है। किसी के पास कोड उदाहरण है कि यह कैसे करें? मुझे संदेह है कि ब्लॉक को मुख्य थ्रेड के अलावा एक अलग थ्रेड पर होना चाहिए? साथ ही, मान लीजिए कि मेरे पास async विधि के पीछे स्रोत कोड तक पहुंच नहीं है। धन्यवाद!

+4

पूरा होने हैंडलर एक ही धागा कॉल dispatch_semaphore_wait आप वास्तव में धागा गतिरोध क्योंकि पूरा होने के ब्लॉक प्रतीक्षा से धागा बाहर निकलता है जब तक क्रियान्वित नहीं किया जा सकता है पर निष्पादित किया जाता है। क्या आप इसे मुख्य धागे पर करने की कोशिश कर रहे हैं? लंबे समय तक मुख्य धागे को अवरुद्ध करना बेहतर नहीं है क्योंकि इसे लगातार संदेशों को प्रेषित करना होगा। – yurish

+0

यदि, @yurish द्वारा संदिग्ध होने के नाते, आप हैंडलर को मुख्य प्रेषण धागे पर कतारबद्ध किया गया है, तो आपको प्रतीक्षा नहीं करनी चाहिए। आपको राज्य कोड के रूप में अपना कोड प्रवाह बनाना होगा और पूरा होने वाले हैंडलर के परिणामस्वरूप जो कुछ भी करने की आवश्यकता है, उसे करना होगा। –

+2

ऐसा करने का कोई सामान्य तरीका नहीं है। जैसा कि अन्य ने कहा है, अगर एसिंक्रोनस कार्य का कुछ हिस्सा रन लूप पर ईवेंट डालने से काम करता है, तो आप हमेशा डेडलॉक करेंगे। आप वास्तव में क्या हासिल करने की कोशिश कर रहे हैं? शायद आपके कोड को ढूढ़ने का एक और तरीका है। – JeremyP

उत्तर

-2

आप अपनी चीजों को असंकालिक रूप से करने के लिए NSOperations का उपयोग करने का प्रयास कर सकते हैं।

8

dispatch_semaphore_wait आपके उदाहरण में मुख्य कतार को अवरुद्ध करता है। NSRunLoop जैसे कुछ अन्य प्रणाली

__block NSString *returnResult; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL); 
dispatch_async(queue,^{ 
    result = [someObject completeTaskSynchronously]; 
}); 

या उपयोग करते हैं,: आप एक अलग कतार में async कार्य प्रेषण कर सकते हैं

__block finished = NO; 
    [self completeTaskWithCompletionHandler:^(NSString *result) { 
     resultResult = result; 
     finished = YES; 
    }]; 
    while (!finished) { 
     // wait 1 second for the task to finish (you are wasting time waiting here) 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; 
    } 
6

एक NSRunLoop का उपयोग करना सबसे आसान यहाँ करने के लिए है।

__block NSString* result = nil; 
[self completeTaskWithCompletionHandler:^(NSString *resultstring) { 
    result = resultstring; 
}]; 
while (!result) { 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
} 
+0

हाँ, मुझे लगता है कि यह अच्छी तरह से काम करता है। मुझे गिटूब पर एक वर्ग एमटीटेस्टसेमफोर भी मिला जो इसे समाहित करता है और इसे अधिक सेमफोर-जैसा बनाता है। धन्यवाद। – kawingkelvin

+0

मुझे आश्चर्य है कि यह सामान्य घटना प्रसंस्करण के साथ कितनी अच्छी तरह से बातचीत करता है? कोर एनीमेशन लेनदेन इत्यादि जैसी चीजें – yurish

+3

यह अच्छी तरह से काम नहीं कर सकती है। रन लूप को वापस आने के लिए ईवेंट को संसाधित करने की आवश्यकता होती है। यदि कोई घटना नहीं है, तो यह केवल "दूर के भविष्य" में वापस आ जाएगी, जो * कभी * नहीं है। इसके अलावा, सूचक 'पहुंच' तक पहुंच थ्रेड सुरक्षित नहीं है। यह गारंटी नहीं है कि एक सूचक शून्य नहीं है और पूरी तरह से प्रारंभ किया गया है। और (संभवतः) एक कंपाइलर को स्मृति स्थान तक पहुंच को अनुकूलित करने और पॉइंटर को उस रजिस्टर में रखने की अनुमति दी जा सकती है जिसे कभी अपडेट नहीं किया जाता है। – CouchDeveloper

1

मुझे लगता है कि नीचे दिया गया बेहतर समाधान NSRunLoop होगा। यह आसान और काम कर रहा है ठीक है।

- (NSString *)getValue { 

    __block BOOL _completed = NO; 
    __block NSString *mValue = nil; 


    [self doSomethingWithCompletionHandler:^(id __nullable value, NSError * __nullable error) { 
     mValue = value; 
     _completed = YES; 
    }]; 

    while (!_completed) { 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 

    return mValue; 
} 
संबंधित मुद्दे