मैं कहूंगा कि क्या एपीआई एक पूरा हैंडलर या सफलता / विफलता ब्लॉकों की एक जोड़ी प्रदान करता है , मुख्य रूप से व्यक्तिगत प्राथमिकता का मामला है।
दोनों दृष्टिकोणों के पक्ष और विपक्ष हैं, हालांकि केवल मामूली अंतर हैं।
इस बात पर विचार करें कि आगे के संस्करण भी हैं, उदाहरण के लिए जहां एक पूर्ण हैंडलर में अंतिम परिणाम या संभावित त्रुटि को मिलाकर केवल एक पैरामीटर हो सकता है :
typedef void (^completion_t)(id result);
- (void) taskWithCompletion:(completion_t)completionHandler;
[self taskWithCompletion:^(id result){
if ([result isKindOfError:[NSError class]) {
NSLog(@"Error: %@", result);
}
else {
...
}
}];
इस हस्ताक्षर का उद्देश्य यह है कि एक पूरा हैंडलर अन्य एपीआई में उदारतापूर्वक उपयोग किया जा सके ।
उदाहरण के लिए श्रेणी में NSArray के लिए एक विधि है forEachApplyTask:completion:
जो क्रमिक रूप से प्रत्येक वस्तु के लिए एक कार्य को आमंत्रित करती है और एक त्रुटि आईएफएफ को तोड़ती है। चूँकि यह विधि अपने आप में अतुल्यकालिक है, इसलिए इसमें एक पूरा हैंडलर भी है:
typedef void (^completion_t)(id result);
typedef void (^task_t)(id input, completion_t);
- (void) forEachApplyTask:(task_t)task completion:(completion_t);
वास्तव में, completion_t
जैसा कि ऊपर बताया गया है कि सभी परिदृश्यों को संभालने के लिए पर्याप्त और पर्याप्त सामान्य है।
हालांकि, एक अतुल्यकालिक कार्य के लिए कॉल-साइट पर इसकी पूर्ण अधिसूचना को इंगित करने के लिए अन्य साधन हैं:
वादे
वादे, जिन्हें "फ्यूचर्स", "स्थगित" या "विलंबित" भी कहा जाता है, एक अतुल्यकालिक कार्य के अंतिम परिणाम का प्रतिनिधित्व करते हैं (यह भी देखें: विकी फ्यूचर्स और वादे )।
प्रारंभ में, एक वादा "लंबित" स्थिति में है। यही है, यह "मूल्य" अभी मूल्यांकन नहीं है और अभी तक उपलब्ध नहीं है।
ऑब्जेक्टिव-सी में, एक वादा एक सामान्य वस्तु होगी जो नीचे दिखाए गए अनुसार एक एसिंक्रोनस विधि से वापस आ जाएगी:
- (Promise*) doSomethingAsync;
! एक वादा की प्रारंभिक स्थिति "लंबित" है।
इस बीच, अतुल्यकालिक कार्य इसके परिणाम का मूल्यांकन करना शुरू कर देते हैं।
यह भी ध्यान दें, कि कोई पूर्ण हैंडलर नहीं है। इसके बजाय, वादा एक अधिक शक्तिशाली साधन प्रदान करेगा जहां कॉल-साइट अतुल्यकालिक कार्य का अंतिम परिणाम प्राप्त कर सकती है, जिसे हम जल्द ही देखेंगे।
अतुल्यकालिक कार्य, जिसने वादे की वस्तु बनाई, अंततः अपने वादे को "हल" करना चाहिए। इसका मतलब है कि, चूंकि कोई कार्य सफल हो सकता है या विफल हो सकता है, यह या तो "पूरा" एक वादा करता है, यह मूल्यांकन किए गए परिणाम को पारित करता है, या यह "अस्वीकार" करता है यह वादा करता है कि इसे पारित करने में विफलता का कारण इंगित करता है।
! एक कार्य को अंततः अपने वादे को हल करना चाहिए।
जब एक प्रॉमिस हल किया गया है, तो यह बदल नहीं सकता है कि यह अब राज्य है, इसके मूल्य सहित।
! एक वादा केवल एक बार हल किया जा सकता है ।
एक बार एक वादा हल हो जाने के बाद, एक कॉल-साइट परिणाम प्राप्त कर सकती है (चाहे वह विफल हो या सफल)। यह कैसे पूरा किया जाता है यह इस बात पर निर्भर करता है कि क्या वादा सिंक्रोनस या एसिंक्रोनस शैली का उपयोग करके लागू किया गया है।
एक वादा या तो करने के लिए एक तुल्यकालिक या एक अतुल्यकालिक शैली जो सुराग में लागू किया जा सकता अवरुद्ध क्रमशः गैर अवरुद्ध अर्थ विज्ञान।
एक तुल्यकालिक शैली में वादे के मूल्य को पुनः प्राप्त करने के लिए, एक कॉल-साइट एक ऐसी विधि का उपयोग करेगी जो वर्तमान धागे को ब्लॉक करेगी जब तक कि एसिंक्रोनस कार्य द्वारा हल नहीं किया गया है और अंतिम परिणाम उपलब्ध है।
एक एसिंक्रोनस शैली में, कॉल-साइट कॉलबैक या हैंडलर ब्लॉकों को पंजीकृत करेगी जो वादा किए जाने के तुरंत बाद कॉल किया जाता है।
यह पता चला कि सिंक्रोनस शैली में कई महत्वपूर्ण नुकसान हैं जो प्रभावी रूप से अतुल्यकालिक कार्यों के गुणों को पराजित करते हैं। मानक सी ++ 11 लिब में "वायदा" के वर्तमान में त्रुटिपूर्ण कार्यान्वयन के बारे में एक दिलचस्प लेख यहां पढ़ा जा सकता है: टूटे हुए वादे-सी ++ 0x वायदा ।
कैसे, उद्देश्य-सी में, एक कॉल-साइट परिणाम प्राप्त करेगा?
खैर, कुछ उदाहरणों को दिखाना शायद सबसे अच्छा है। पुस्तकालयों के एक जोड़े हैं जो एक वादा लागू करते हैं (नीचे लिंक देखें)।
हालाँकि, अगले कोड स्निपेट के लिए, मैं एक विशेष पुस्तकालय के कार्यान्वयन का उपयोग करूंगा, जो GitHub RXPromise पर उपलब्ध है । मैं RXPromise का लेखक हूँ।
अन्य कार्यान्वयन में एक समान एपीआई हो सकता है, लेकिन सिंटैक्स में छोटे और संभवतः सूक्ष्म अंतर हो सकते हैं। RXPromise वादा / ए + विनिर्देशन का एक उद्देश्य-सी संस्करण है जो जावास्क्रिप्ट में वादों के मजबूत और परस्पर कार्यान्वयन के लिए एक खुले मानक को परिभाषित करता है।
नीचे सूचीबद्ध सभी वादा पुस्तकालयों में एसिंक्रोनस शैली लागू होती है।
विभिन्न कार्यान्वयनों के बीच काफी महत्वपूर्ण अंतर हैं। RXPromise आंतरिक रूप से डिस्पैच लिब का उपयोग करता है, पूरी तरह से सुरक्षित थ्रेड है, बेहद हल्का है, और रद्द करने की तरह कई अतिरिक्त उपयोगी सुविधाएं भी प्रदान करता है।
एक कॉल-साइट "पंजीकरण" संचालकों के माध्यम से अतुल्यकालिक कार्य का अंतिम परिणाम प्राप्त करती है। "वादा / ए + विनिर्देश" विधि को परिभाषित करता है then
।
प्रक्रिया then
RXPromise के साथ यह इस प्रकार दिखता है:
promise.then(successHandler, errorHandler);
जहाँ successHandler एक ऐसा ब्लॉक है जिसे वादा पूरा होने पर बुलाया जाता है और त्रुटिहैंडलर एक ब्लॉक होता है जिसे वादा "अस्वीकार" होने पर बुलाया जाता है।
! then
अंतिम परिणाम प्राप्त करने और एक सफलता या एक त्रुटि हैंडलर को परिभाषित करने के लिए उपयोग किया जाता है।
RXPromise में, हैंडलर ब्लॉकों में निम्नलिखित हस्ताक्षर हैं:
typedef id (^success_handler_t)(id result);
typedef id (^error_handler_t)(NSError* error);
Success_handler का एक पैरामीटर परिणाम है जो स्पष्ट रूप से अतुल्यकालिक कार्य का अंतिम परिणाम है। इसी तरह, error_handler में एक पैरामीटर त्रुटि है जो कि असिंक्रोनस कार्य द्वारा रिपोर्ट की गई त्रुटि है जब यह विफल हुआ।
दोनों ब्लॉक का रिटर्न वैल्यू है। यह वापसी मूल्य के बारे में क्या है, जल्द ही स्पष्ट हो जाएगा।
RXPromise में, then
एक संपत्ति है जो एक ब्लॉक लौटाता है। इस ब्लॉक के दो पैरामीटर हैं, सफलता हैंडलर ब्लॉक और त्रुटि हैंडलर ब्लॉक। हैंडलर को कॉल-साइट द्वारा परिभाषित किया जाना चाहिए।
! हैंडलर को कॉल-साइट द्वारा परिभाषित किया जाना चाहिए।
तो, अभिव्यक्ति promise.then(success_handler, error_handler);
का संक्षिप्त रूप है
then_block_t block promise.then;
block(success_handler, error_handler);
हम और भी संक्षिप्त कोड लिख सकते हैं:
doSomethingAsync
.then(^id(id result){
…
return @“OK”;
}, nil);
कोड पढ़ता है: "जब यह सफल हो जाता है, तब सफलता हैंडलर को निष्पादित करें " doSomethingAsync निष्पादित करें।
यहां, त्रुटि हैंडलर nil
जिसका अर्थ है, त्रुटि के मामले में, इस वादे में संभाला नहीं जाएगा।
एक और महत्वपूर्ण तथ्य यह है कि संपत्ति से लौटाए गए ब्लॉक को कॉल करने then
पर एक वादा वापस आएगा:
! then(...)
प्रतिज्ञा देता है
जब प्रॉपर्टी से ब्लॉक वापस किया जाता है then
, तो "रिसीवर" एक नया वादा करता है, एक बच्चा वादा करता है। रिसीवर माता-पिता का वादा बन जाता है ।
RXPromise* rootPromise = asyncA();
RXPromise* childPromise = rootPromise.then(successHandler, nil);
assert(childPromise.parent == rootPromise);
इसका क्या मतलब है?
खैर, इसके कारण हम अतुल्यकालिक कार्यों को "श्रृंखला" कर सकते हैं जो प्रभावी रूप से क्रमिक रूप से निष्पादित होते हैं।
इसके अलावा, या तो हैंडलर का रिटर्न वैल्यू रिटर्न किए गए वादे का "मूल्य" बन जाएगा। इसलिए, यदि कार्य अंतिम परिणाम @ "ओके" के साथ सफल होता है, तो लौटा हुआ वादा "" ओके "" मान के साथ "हल" (जो कि "पूरा") होगा:
RXPromise* returnedPromise = asyncA().then(^id(id result){
return @"OK";
}, nil);
...
assert([[returnedPromise get] isEqualToString:@"OK"]);
इसी तरह, जब अतुल्यकालिक कार्य विफल हो जाता है, तो लौटा हुआ वादा हल हो जाएगा (जो कि "अस्वीकृत" है) एक त्रुटि के साथ।
RXPromise* returnedPromise = asyncA().then(nil, ^id(NSError* error){
return error;
});
...
assert([[returnedPromise get] isKindOfClass:[NSError class]]);
हैंडलर भी एक और वादा वापस कर सकता है। उदाहरण के लिए जब वह हैंडलर किसी अन्य अतुल्यकालिक कार्य को अंजाम देता है। इस तंत्र के साथ हम अतुल्यकालिक कार्यों को "चेन" कर सकते हैं:
RXPromise* returnedPromise = asyncA().then(^id(id result){
return asyncB(result);
}, nil);
! हैंडलर ब्लॉक का रिटर्न मूल्य बच्चे के वादे का मूल्य बन जाता है।
यदि कोई बच्चा वादा नहीं करता है, तो रिटर्न वैल्यू का कोई प्रभाव नहीं पड़ता है।
एक और अधिक जटिल उदाहरण:
यहाँ, हम पर अमल asyncTaskA
, asyncTaskB
, asyncTaskC
और asyncTaskD
क्रमिक रूप से - और प्रत्येक अनुवर्ती कार्य इनपुट के रूप में पूर्ववर्ती कार्य का परिणाम लेता है:
asyncTaskA()
.then(^id(id result){
return asyncTaskB(result);
}, nil)
.then(^id(id result){
return asyncTaskC(result);
}, nil)
.then(^id(id result){
return asyncTaskD(result);
}, nil)
.then(^id(id result){
// handle result
return nil;
}, nil);
इस तरह की "श्रृंखला" को "निरंतरता" भी कहा जाता है।
गलती संभालना
वादे त्रुटियों को संभालने के लिए विशेष रूप से आसान बनाते हैं। यदि माता-पिता के वादे में कोई त्रुटि हैंडलर परिभाषित नहीं है, तो माता-पिता से बच्चे तक त्रुटियों को "अग्रेषित" किया जाएगा। जब तक कोई बच्चा इसे नहीं संभालता, श्रृंखला में त्रुटि को आगे भेज दिया जाएगा। इस प्रकार, उपरोक्त श्रृंखला होने पर, हम एक और "निरंतरता" जोड़कर त्रुटि से निपटने को लागू कर सकते हैं जो संभावित त्रुटि से संबंधित है जो कहीं भी हो सकता है :
asyncTaskA()
.then(^id(id result){
return asyncTaskB(result);
}, nil)
.then(^id(id result){
return asyncTaskC(result);
}, nil)
.then(^id(id result){
return asyncTaskD(result);
}, nil)
.then(^id(id result){
// handle result
return nil;
}, nil);
.then(nil, ^id(NSError*error) {
NSLog(@“”Error: %@“, error);
return nil;
});
यह अपवाद हैंडलिंग के साथ संभवतः अधिक परिचित तुल्यकालिक शैली के समान है:
try {
id a = A();
id b = B(a);
id c = C(b);
id d = D(c);
// handle d
}
catch (NSError* error) {
NSLog(@“”Error: %@“, error);
}
सामान्य रूप से वादे में अन्य उपयोगी विशेषताएं हैं:
उदाहरण के लिए, एक वादे के संदर्भ में, then
एक के रूप में वांछित के रूप में कई संचालकों "रजिस्टर" कर सकते हैं। RXPromise में, रजिस्टर करने वाले हैंडलर किसी भी समय और किसी भी थ्रेड से हो सकते हैं क्योंकि यह पूरी तरह से थ्रेड-सुरक्षित है।
RXPromise में कुछ अधिक उपयोगी कार्यात्मक विशेषताएं हैं, जो कि वादा / A + विनिर्देश द्वारा आवश्यक नहीं है। एक "रद्दीकरण" है।
यह पता चला कि "रद्द करना" एक अमूल्य और महत्वपूर्ण विशेषता है। उदाहरण के लिए एक कॉल-साइट एक वादे के संदर्भ में यह cancel
संदेश भेजने के लिए यह इंगित करने के लिए कि यह अब अंतिम परिणाम में कोई दिलचस्पी नहीं है।
बस एक अतुल्यकालिक कार्य की कल्पना करें जो वेब से एक छवि लोड करता है और जिसे एक दृश्य नियंत्रक में प्रदर्शित किया जाएगा। यदि उपयोगकर्ता वर्तमान दृश्य नियंत्रक से दूर जाता है, तो डेवलपर उस कोड को लागू कर सकता है जो छवि को रद्द संदेश भेजता है , जो बदले में HTTP अनुरोध ऑपरेशन द्वारा परिभाषित त्रुटि हैंडलर को ट्रिगर करता है जहां अनुरोध रद्द हो जाएगा।
RXPromise में, एक रद्द संदेश केवल एक अभिभावक से उसके बच्चों को भेजा जाएगा, लेकिन इसके विपरीत नहीं। यही है, एक "मूल" वादा सभी बच्चों के वादों को रद्द कर देगा। लेकिन एक बच्चा वादा केवल "शाखा" को रद्द कर देगा जहां वह माता-पिता है। यदि कोई वादा पहले ही हल कर लिया गया है, तो रद्द संदेश भी बच्चों को भेज दिया जाएगा।
एक अतुल्यकालिक कार्य स्वयं अपने वादे के लिए हैंडलर को पंजीकृत कर सकता है , और इस प्रकार यह पता लगा सकता है कि किसी और ने इसे कब रद्द कर दिया। यह समय से पहले एक संभवतः लंबा और महंगा कार्य करना बंद कर सकता है।
GitHub पर दिए गए ऑब्जेक्टिव-सी में वादों के कुछ अन्य कार्यान्वयन यहां दिए गए हैं:
https://github.com/Schoonology/aplus-objc
https://github.com/affablebloke/deferred-objective-c
https://github.com/bww/FutureKit
https://github.com/jkubbk/JKPromises
https://github.com/Strilanc/ObjC-CollapsingFutures
https://github.com/b52/OMPromises
https://github.com/mproberts/objc-promise
https://github.com/kassaspieter/Promise
https: // github.com/jameswomack/Promise
https://github.com/nilfs/promise-objc
https://github.com/mxcl/PromiseKit
https://github.com/apleshkov/promises-aplus
https: // github.com/KptainO/Rebelle
और मेरा अपना कार्यान्वयन: RXPromise ।
यह सूची पूरी होने की संभावना नहीं है!
अपनी परियोजना के लिए तीसरा पुस्तकालय चुनते समय, कृपया ध्यान से देखें कि क्या पुस्तकालय का कार्यान्वयन नीचे सूचीबद्ध पूर्वापेक्षाओं का पालन करता है:
एक विश्वसनीय वादा पुस्तकालय शाल सुरक्षित होना चाहिए!
यह सभी अतुल्यकालिक प्रसंस्करण के बारे में है, और हम कई सीपीयू का उपयोग करना चाहते हैं और जब भी संभव हो अलग-अलग थ्रेड पर निष्पादित करें। सावधान रहें, अधिकांश कार्यान्वयन थ्रेड सुरक्षित नहीं हैं!
हैंडलर SHALL को अतुल्यकालिक रूप से बुलाया जाना चाहिए जो कॉल-साइट का सम्मान करता है! हमेशा, और कोई बात नहीं!
किसी भी सभ्य कार्यान्वयन को अतुल्यकालिक कार्यों को लागू करते समय एक बहुत ही सख्त पैटर्न का पालन करना चाहिए। कई कार्यान्वयन "का अनुकूलन" मामले में, जहां एक हैंडलर द्वारा सक्रिय किया जाएगा करते हैं तुल्यकालिक जब वादा पहले से ही हल हो गई है जब हैंडलर पंजीकृत होगा। यह सभी प्रकार के मुद्दों का कारण बन सकता है। देखें Zalgo जारी नहीं करते! ।
एक वादे को रद्द करने के लिए एक तंत्र भी होना चाहिए।
एक अतुल्यकालिक कार्य को रद्द करने की संभावना अक्सर आवश्यकता विश्लेषण में उच्च प्राथमिकता के साथ एक आवश्यकता बन जाती है। यदि नहीं, तो सुनिश्चित करें कि ऐप जारी होने के कुछ समय बाद किसी उपयोगकर्ता से एन्हांसमेंट अनुरोध दर्ज किया जाएगा। कारण स्पष्ट होना चाहिए: कोई भी कार्य जो समाप्त होने में बहुत लंबा हो सकता है या समाप्त हो सकता है, उपयोगकर्ता द्वारा या समय-समय पर रद्द किया जाना चाहिए। एक अच्छा वादा पुस्तकालय को रद्द करने का समर्थन करना चाहिए।