2012-06-12 12 views
6

Transitioning to ARC Release Notesहमें __block चर को शून्य में क्यों सेट करना है?

उपयोग लाइफटाइम क्वालिफायर से मजबूत संदर्भ साइकिल

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

मैन्युअल संदर्भ गणना मोड में, __block id x; को बनाए रखने का प्रभाव नहीं है। एआरसी मोड में, __block id x;x को बनाए रखने के लिए डिफ़ॉल्ट (केवल अन्य सभी मानों की तरह)। मैन्युअल संदर्भ गिनती मोड एआरसी के तहत व्यवहार प्राप्त करने के लिए, आप __unsafe_unretained __block id x; का उपयोग कर सकते हैं। नाम __unsafe_unretained का तात्पर्य है, हालांकि गैर-बनाए रखा चर खतरनाक है (क्योंकि यह लटक सकता है) और इसलिए निराश है। दो बेहतर विकल्प या तो __weak का उपयोग करना है (यदि आपको आईओएस 4 या ओएस एक्स v10.6 का समर्थन करने की आवश्यकता नहीं है), या __block मान को बनाए रखने के चक्र को तोड़ने के लिए nil पर सेट करें।

ठीक है, तो __block चर के बारे में क्या अलग है?

क्यों nil पर सेट क्यों करें? __block चर दो बार बनाए रखा है? सभी संदर्भ कौन रखता है? खंड? ढेर? ढेर? सूत्र? क्या?

निम्नलिखित कोड खंड इस समस्या को एक पैटर्न का उपयोग करके दिखाता है जिसे कभी-कभी मैन्युअल संदर्भ गणना में उपयोग किया जाता है।

MyViewController *myController = [[MyViewController alloc] init…]; 

// ... 

myController.completionHandler = ^(NSInteger result) { 
    [myController dismissViewControllerAnimated:YES completion:nil]; 
}; 

[self presentViewController:myController animated:YES completion:^{ 
    [myController release]; 
}]; 

के रूप में वर्णित है, बजाय, आप एक __block क्वालीफायर का उपयोग करें और पूरा होने हैंडलर में nil को myController चर सेट कर सकते हैं:

MyViewController * __block myController = [[MyViewController alloc] init…]; //Why use __block. my controller is not changed at all 

// ... 

myController.completionHandler = ^(NSInteger result) { 
    [myController dismissViewControllerAnimated:YES completion:nil]; 

    myController = nil; //Why set to nil here? Is __block variable retained twice? Who hold all the reference? The block? The heap? The stack? The thread? The what? 
}; 

भी क्यों myController संकलक द्वारा nil पर सेट नहीं है। हमें ऐसा क्यों करना है? ऐसा लगता है कि जब संकलक समाप्त हो जाता है तो मेरे नियंत्रक को फिर से उपयोग नहीं किया जाएगा जब संकलक प्रकार का पता चल जाएगा।

उत्तर

14

आप इस फार्म के कोड है जब:

object.block = ^{ 
    // reference object from inside the block 
    [object someMethodOrProperty]; 
}; 

object बनाए रखने या ब्लॉक आप इसे देने के लिए कॉपी कर देंगे। लेकिन ब्लॉक स्वयं भी object बनाए रखेगा क्योंकि इसे ब्लॉक के भीतर से दृढ़ता से संदर्भित किया जाता है। यह एक बरकरार चक्र है। ब्लॉक निष्पादित करने के बाद भी, संदर्भ चक्र अभी भी मौजूद है और न ही ऑब्जेक्ट और न ही ब्लॉक को हटाया जा सकता है। याद रखें कि एक ब्लॉक को कई बार बुलाया जा सकता है, इसलिए यह केवल एक बार निष्पादित करने के बाद संदर्भों के सभी चरों को भूल नहीं सकता है।

इस चक्र को तोड़ने के लिए, आप object को __block चर के रूप में परिभाषित कर सकते हैं, जो आपको ब्लॉक के अंदर से अपना मान बदलने की अनुमति देता है, उदा।nil में बदलने चक्र को तोड़ने के:

__block id object = ...; 
object.block = ^{ 
    // reference object from inside the block 
    [object someMethodOrProperty]; 

    object = nil; 
    // At this point, the block no longer retains object, so the cycle is broken 
}; 

जब हम ब्लॉक के अंत में nil को object असाइन करते हैं, ब्लॉक अब object बनी रहेगी और बनाए रखने के चक्र टूट गया है। यह दोनों वस्तुओं को नष्ट करने की अनुमति देता है।

इसका एक ठोस उदाहरण NSOperation की completionBlock संपत्ति के साथ है। आप भी इन चक्र को बनाए रखने को तोड़ने के लिए उपयोग कर सकते हैं प्रलेखन का वर्णन करता है

__block NSOperation *op = [self operationForProcessingSomeData]; 
op.completionBlock = ^{ 
    // since we strongly reference op here, a retain cycle is created 
    [self operationFinishedWithData:op.processedData]; 

    // break the retain cycle! 
    op = nil; 
} 

हैं, वहाँ अन्य तकनीकों का एक नंबर रहे हैं: आप एक ऑपरेशन के परिणाम तक पहुँचने के लिए completionBlock उपयोग करते हैं, आप चक्र कि बनाई गई है बनाए रखने को तोड़ने की जरूरत है । उदाहरण के लिए, आपको एआरसी कोड में गैर-एआरसी कोड में एक अलग तकनीक का उपयोग करने की आवश्यकता होगी।

+0

"लेकिन ब्लॉक स्वयं ऑब्जेक्ट को भी बनाए रखेगा क्योंकि इसे ब्लॉक के भीतर से दृढ़ता से संदर्भित किया जाता है।" क्यूं कर? बंद। –

+0

__block जोड़ने से कैसे कोई फर्क पड़ता है? –

+0

जब कोई ब्लॉक किसी ऑब्जेक्ट-सी ऑब्जेक्ट में पॉइंटर को कैप्चर करता है, तब तक उस ऑब्जेक्ट को तब तक बनाए रखा जाएगा जब तक आप '__weak' या '__unsafe_unretained' (या गैर-एआरसी कोड में' __block') का उपयोग न करें। –

0

मैं इस समाधान

typeof(self) __weak weakSelf = self; 
self.rotationBlock = ^{ 
    typeof (weakSelf) __strong self = weakSelf; 

    [self yourCodeThatReferenceSelf]; 
}; 

क्या होता है कि ब्लॉक एक कमजोर संदर्भ के रूप में स्वयं पर कब्जा होगा और वहाँ चक्र नहीं बनाए रखने की जाएगी पसंद करते हैं। ब्लॉक के अंदर स्वयं को आपके कोड चलाने से पहले __strong self = कमजोर के रूप में फिर से परिभाषित किया जाता है। यह आपके ब्लॉक को चलाने के दौरान स्वयं को रिहा होने से रोकता है।

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