"__Block" कीवर्ड का क्या अर्थ है?


446

__blockObjective-C में कीवर्ड का वास्तव में क्या मतलब है? मुझे पता है कि यह आपको ब्लॉकों के भीतर चर को संशोधित करने की अनुमति देता है, लेकिन मैं जानना चाहता हूं ...

  1. वास्तव में यह संकलक को क्या बताता है?
  2. क्या यह कुछ और करता है?
  3. अगर यह सब ऐसा होता है, तो पहले स्थान पर इसकी आवश्यकता क्यों है?
  4. क्या यह डॉक्स में कहीं है? (मैं यह नहीं मिल सकता है)।

3
जाँच यहां , और "ब्लाकों और चर" खंड।


1
@ कोड बंदर: मैं विशेष रूप से कीवर्ड के बारे में पूछ रहा था, सामान्य रूप से वाक्य रचना नहीं। तो नहीं लगता कि यह वास्तव में एक डुप्लिकेट है।
मझिस्वामी

3
@ कोड बंदर: नहीं, यह कोई डुप्लिकेट नहीं है। आपके द्वारा उल्लेखित प्रश्न के बारे __blockमें बात नहीं करता है ।
डार्कडस्ट

3
और अगर कोई सोच रहा है कि ऑब्जेक्टिव-सी का __blockस्विफ्ट में अनुवाद कैसे होना चाहिए: "क्लोजर [स्विफ्ट में] ब्लॉक के रूप में समान कैप्चर शब्दार्थ है [ऑब्जेक्टिव-सी में] लेकिन एक प्रमुख तरीके से भिन्न होते हैं: वेरिएबल्स कॉपी किए जाने के बजाय परस्पर भिन्न होते हैं। दूसरे शब्दों में, उद्देश्य-सी में __ब्लॉक का व्यवहार स्विफ्ट में चर के लिए डिफ़ॉल्ट व्यवहार है। " एप्पल की पुस्तक से: स्विफ्ट विद कोको और ऑब्जेक्टिव-सी (स्विफ्ट 2.2) का उपयोग करना।
जरी कीनेलेन

जवाबों:


543

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

एक उदाहरण और अधिक जानकारी के लिए, Apple के ब्लॉक प्रोग्रामिंग टॉपिक्स में __block स्टोरेज टाइप देखें ।

महत्वपूर्ण उदाहरण यह है:

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;

{
    NSInteger localCounter = 42;
    __block char localCharacter;

    void (^aBlock)(void) = ^(void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter fixed at block creation
        localCharacter = 'a'; // sets localCharacter in enclosing scope
    };

    ++localCounter; // unseen by the block
    localCharacter = 'b';

    aBlock(); // execute the block
    // localCharacter now 'a'
}

इस उदाहरण में, दोनों localCounterऔर localCharacterब्लॉक कहा जाता है से पहले संशोधित कर रहे हैं। हालाँकि, ब्लॉक के अंदर, केवल संशोधन localCharacterदिखाई देगा, __blockकीवर्ड के लिए धन्यवाद । इसके विपरीत, ब्लॉक संशोधित कर सकता है localCharacterऔर यह संशोधन ब्लॉक के बाहर दिखाई देता है।


8
उत्कृष्ट, संक्षिप्त विवरण, और एक बहुत ही उपयोगी उदाहरण। धन्यवाद!
इवान स्टोन

1
ABlock लोकल एनकाउंटर को कैसे संशोधित करता है? यह केवल काउंटरग्लोबल को संशोधित करने के लिए लगता है। धन्यवाद
CommaToast

8
यह संशोधित नहीं करता है localCounter, लेकिन यह संशोधित करता है localCharacter। इसके अलावा, localCounterब्लॉक में दिए गए मूल्य पर ध्यान दें : यह 42 है, भले ही ब्लॉक कहे जाने से पहले वेरिएबल बढ़ जाता है, लेकिन ब्लॉक बनाए जाने के बाद (जब मान "कैप्चर" हुआ)।
डार्कडस्ट

1
यह एक सहायक स्पष्टीकरण है - हालांकि - क्या आप समझा सकते हैं कि आपकी व्याख्या में विरोधाभासी बयान क्या प्रतीत होते हैं? आप ऊपर कहते हैं कि "aBlock को संशोधित करता है ... localCounter" और फिर टिप्पणियों में आप कहते हैं "[aBlock] लोकल एनकाउंटर को संशोधित नहीं करता है।" यह किसका है? यदि यह "संशोधित नहीं" है, तो क्या आपके उत्तर को संपादित किया जाना चाहिए?
प्रैक्सिटेल्स

2
सामान्य तौर पर, __block के बिना var को मान द्वारा कैप्चर किया जाएगा और ब्लॉक के "वातावरण" में पैक किया जाएगा, जब ब्लॉक बनाया जाता है। लेकिन जब भी वे किसी ब्लॉक के अंदर या बाहर उपयोग किए जाते हैं, उन्हें कैप्चर नहीं किया जाएगा, जैसा कि उन्हें संदर्भित किया जाता है।
jchnxu

27

@bbum एक ब्लॉग पोस्ट में गहराई से ब्लॉक को कवर करता है और __ब्लॉक स्टोरेज प्रकार पर छूता है।

__ब्लॉक एक अलग भंडारण प्रकार है

जैसे स्थैतिक, ऑटो और वाष्पशील, __ब्लॉक एक भंडारण प्रकार है। यह संकलक को बताता है कि चर के भंडारण को अलग तरीके से प्रबंधित किया जाना है।

...

हालांकि, __block चर के लिए, ब्लॉक बरकरार नहीं रखता है। आवश्यकतानुसार इसे जारी रखना और जारी करना आपके ऊपर है।
...

उपयोग के मामलों के लिए आप __blockकभी-कभी चक्र बनाए रखने से बचने के लिए उपयोग किया जाता है क्योंकि यह तर्क को बनाए नहीं रखता है। एक सामान्य उदाहरण स्वयं का उपयोग कर रहा है।

//Now using myself inside a block will not 
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;

चक्र जारी रखने के बारे में अधिक जानकारी के लिए इस पोस्ट को देखें: benscheirman.com/2012/01/… । क्या __weakइस विशिष्ट मामले में भी पर्याप्त होगा ? यह शायद थोड़ा स्पष्ट है ...
हरि करम सिंह

17
अंत में दावा है कि मजबूत संदर्भ चक्र से बचने के लिए __block का उपयोग किया जा सकता है (उर्फ चक्र को बनाए रखना) एआरसी संदर्भ में सादा गलत है। इस तथ्य के कारण कि एआरसी __ब्लॉक में चर को दृढ़ता से संदर्भित किया जाता है, यह वास्तव में उनके कारण होने की अधिक संभावना है। stackoverflow.com/a/19228179/189006
कृष्णन

10

आम तौर पर जब आप __ब्लॉक का उपयोग नहीं करते हैं, तो ब्लॉक वेरिएबल को कॉपी (रिटेन) करेगा, इसलिए भले ही आप वेरिएबल को संशोधित कर दें, ब्लॉक की पुरानी ऑब्जेक्ट तक पहुंच है।

NSString* str = @"hello";
void (^theBlock)() = ^void() {
    NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints @"hello"

इन 2 मामलों में आपको __block की आवश्यकता है:

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

__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
    str = @"how are you";
};
theBlock();
NSLog(@"%@", str); //prints "how are you"

2.अगर आप ब्लॉक घोषित करने के बाद वेरिएबल को संशोधित करना चाहते हैं और आप ब्लॉक को बदलाव देखने की उम्मीद करते हैं:

__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
    NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints "how are you"

8

__ब्लॉक एक स्टोरेज क्वालिफायर है जिसे दो तरीकों से इस्तेमाल किया जा सकता है:

  1. ऐसे निशान जो एक चर एक भंडारण में रहते हैं जो मूल चर के शाब्दिक दायरे और उस दायरे के भीतर घोषित किए गए किसी भी ब्लॉक के बीच साझा किया जाता है। और क्लैंग इस चर का प्रतिनिधित्व करने के लिए एक संरचना उत्पन्न करेगा, और संदर्भ द्वारा इस संरचना का उपयोग करेगा (मूल्य से नहीं)।

  2. MRC में, __block का उपयोग ब्लॉक वंचित ऑब्जेक्ट चर बनाए रखने से बचने के लिए किया जा सकता है। सावधान कि यह एआरसी के लिए काम नहीं करता है। एआरसी में, आपको इसके बजाय __weak का उपयोग करना चाहिए ।

आप विस्तृत जानकारी के लिए ऐप्पल डॉक्टर का उल्लेख कर सकते हैं ।


6

__blockएक स्टोरेज टाइप है जो स्कोप वैरिएबल में बनाने के लिए उपयोग किया जाता है, अधिक स्पष्ट रूप से यदि आप इस स्पेसिफायर के साथ एक वैरिएबल की घोषणा करते हैं, तो इसका संदर्भ ब्लॉक में पढ़ने के लिए होगा न कि केवल अधिक विवरण के लिए कॉपी करें आईओएस में ब्लॉक प्रोग्रामिंग देखें


2

आशा है कि यह आपकी मदद करेगा

मान लें कि हमारे पास एक कोड है:

{
     int stackVariable = 1;

     blockName = ^()
     {
      stackVariable++;
     }
}

यह "वैरिएबल असाइन नहीं है" जैसी त्रुटि देगा क्योंकि ब्लॉक के अंदर स्टैक वेरिएबल डिफ़ॉल्ट अपरिवर्तनीय है।

घोषणा के आगे __ब्लॉक (स्टोरेज मोडिफायर) जोड़ना यह ब्लॉक के अंदर परिवर्तनशील बनाता है __block int stackVariable=1;


1

से ब्लॉक भाषा युक्ति :

नए ब्लॉक प्रकार के अलावा, हम स्थानीय वेरिएबल्स के लिए एक नया स्टोरेज क्वालिफायर, __ब्लॉक भी पेश करते हैं। [testme: __block घोषणा एक ब्लॉक शाब्दिक के भीतर] __block भंडारण क्वालीफायर मौजूदा स्थानीय भंडारण क्वालिफायर ऑटो, रजिस्टर, और स्थैतिक के लिए विशेष रूप से अनन्य है। [testme] __block द्वारा योग्य वैरिएबल जैसे कि वे आवंटित भंडारण में कार्य करते हैं और यह भंडारण है। स्वचालित रूप से उक्त चर के अंतिम उपयोग के बाद बरामद किया गया। एक कार्यान्वयन एक अनुकूलन का चयन कर सकता है जहां भंडारण शुरू में स्वचालित होता है और केवल संदर्भित क्षेत्र के ब्लॉक_कोपी पर भंडारण (हीप) को "स्थानांतरित" किया जाता है। इस तरह के चर को सामान्य चर के रूप में परिवर्तित किया जा सकता है।

उस स्थिति में जहां एक __ब्लॉक वैरिएबल एक ब्लॉक होता है, को यह मानना ​​चाहिए कि __ब्लॉक वैरिएबल आवंटित भंडारण में रहता है और जैसे कि एक ब्लॉक को संदर्भित करने के लिए माना जाता है जो कि आवंटित भंडारण में भी है (यह एक ब्लॉक_कोपी ऑपरेशन का परिणाम है)। इसके बावजूद अगर कोई कार्यान्वयन ब्लॉक के लिए प्रारंभिक स्वचालित भंडारण प्रदान करता है, तो Block_copy या Block_release करने का कोई प्रावधान नहीं है। यह साझा चर को अद्यतन करने के लिए संभावित रूप से कई थ्रेड्स की अंतर्निहित दौड़ की स्थिति और पुराने मानों को निपटाने और नए लोगों को कॉपी करने के आसपास सिंक्रनाइज़ेशन की आवश्यकता के कारण है। इस तरह की सिंक्रनाइज़ेशन इस भाषा विनिर्देश के दायरे से परे है।

__Block चर का संकलन क्या करना चाहिए, इसके विवरण के लिए , खंड कार्यान्वयन युक्ति , खंड 2.3 देखें।


आपके लिंक दोनों मृत हैं
बेन लेगियरियो

यह वास्तव में एक उत्तर नहीं है और इसे हटा दिया या हटाया जा सकता है। धन्यवाद!
दान रोसेनस्टार्क

0

इसका मतलब यह है कि यह जिस चर का उपसर्ग है वह एक ब्लॉक के भीतर इस्तेमाल होने के लिए उपलब्ध है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.