2013-09-26 14 views
38

मेरे पास आईओएस में स्वयं ब्लॉक में मजबूत और कमजोर संदर्भों के बारे में एक प्रश्न है। मैं जानता हूँ कि उचित तरीके से एक ब्लॉक के अंदर स्वयं को संदर्भित करने के इस तरह ब्लॉक के अंदर है कि कमजोर संदर्भ के लिए एक मजबूत संदर्भ, ब्लॉक के बाहर एक कमजोर संदर्भ बनाने के लिए है, और उसके बाद:आईओएस ब्लॉक और स्वयं के लिए मजबूत/कमजोर संदर्भ

__weak typeof(self) weakSelf = self; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ 
    typeof(self) strongSelf = weakSelf; 
    NSLog(@"%@", strongSelf.someProperty); 
}); 

हालांकि, अगर ऐसा होता आपके पास घोंसला वाले ब्लॉक हैं? क्या संदर्भों का एक सेट पर्याप्त है? या क्या आपको प्रत्येक ब्लॉक के लिए एक नया सेट चाहिए? उदाहरण के लिए, निम्नलिखित में से कौन सा सही है?

यह:

__weak typeof(self) weakSelf = self; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ 
    typeof(self) strongSelf = weakSelf; 
    NSLog(@"%@", strongSelf.someProperty); 
    dispatch_async(dispatch_get_main_queue(),^{ 
     strongSelf.view.frame = CGRectZero; 
    }); 
}); 

या इस:

__weak typeof(self) weakSelf = self; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ 
     typeof(self) strongSelf = weakSelf; 
     NSLog(@"%@", strongSelf.someProperty); 
     __weak typeof(strongSelf) weakSelf1 = strongSelf; 
     dispatch_async(dispatch_get_main_queue(),^{ 
      typeof(strongSelf) strongSelf1 = weakSelf1; 
      strongSelf1.view.frame = CGRectZero; 
     }); 
    }); 

कोई भी जानकारी या स्पष्टीकरण बहुत सराहना कर रहा है!

+0

हमें ब्लॉक के अंदर कमज़ोर के लिए एक मजबूत संदर्भ क्यों बनाना चाहिए? – BergP

उत्तर

52

आपको कमजोर संदर्भों के दो सेट बनाने की आवश्यकता नहीं है। आप ब्लॉक के साथ क्या बचाना चाहते हैं वह एक सतत चक्र-दो वस्तुएं हैं जो एक दूसरे को अनावश्यक रूप से जीवित रखते हैं।

अगर मैं इस संपत्ति के साथ एक वस्तु है:

@property (strong) void(^completionBlock)(void); 

और मैं इस विधि है:

- (void)doSomething 
{ 
    self.completionBlock = ^{ 
     [self cleanUp]; 
    }; 

    [self doLongRunningTask]; 
} 

ब्लॉक जिंदा रखा जाएगा जब मैं completionBlock संपत्ति में संग्रहीत। लेकिन चूंकि यह ब्लॉक के अंदर self का संदर्भ देता है, इसलिए ब्लॉक self जीवित रहेगा जब तक कि यह दूर न हो जाए- लेकिन ऐसा नहीं होगा क्योंकि वे दोनों एक-दूसरे का संदर्भ दे रहे हैं।

इस विधि में:

- (void)doSomething 
{ 
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
     [self cleanUp]; 
    }]; 

    [self doLongRunningTask]; 
} 

आप self के लिए एक कमजोर संदर्भ बनाने की जरूरत नहीं है। ब्लॉक self जीवित रखेगा, क्योंकि यह self संदर्भित करता है, लेकिन चूंकि हम कर रहे हैं ब्लॉक को [NSOperationQueue mainQueue], self ब्लॉक को जीवंत नहीं रख रहा है।

उम्मीद है कि इससे मदद मिलती है।

22

दोनों संरचनाएं ठीक हैं। यह सिर्फ आपके इरादे पर निर्भर करता है। बाहरी ब्लॉक शुरू होने के बाद ऑब्जेक्ट (ए) जारी होने पर आप क्या करना चाहते हैं, लेकिन (बी) मुख्य कतार पर आंतरिक ब्लॉक शुरू होने से पहले? यदि आप नहीं चाहते हैं कि यह इस परिदृश्य में बनाए रखा जाए (जो मुझे लगता है कि आपका इरादा था, यह देखते हुए कि आप इस स्थान पर weakSelf अभ्यास के माध्यम से जा रहे हैं), फिर अपने अंतिम उदाहरण का उपयोग करें, जहां आपके पास दूसरा कमजोर पॉइंटर है। अन्यथा आप अपने अन्य उदाहरण का उपयोग कर सकते हैं।

कहा करने के बाद कि, टिप्पणियों के एक जोड़े:

  1. यह एक forgone निष्कर्ष आप पहली जगह में इस weakSelf पैटर्न का उपयोग करने के लिए है कि नहीं है। कुछ लोग गलती से सोचते हैं कि में है जो एक मजबूत संदर्भ चक्र (ए.के.ए. बनाए रखने चक्र) से बचने के लिए इस weakSelf पैटर्न का उपयोग करने के लिए है। लेकिन यह कोड नमूना एक मजबूत संदर्भ चक्र का गठन नहीं करता है। प्रेषित कोड निष्पादित करते समय यह ऑब्जेक्ट को बरकरार रखता है, जो कि एक बहुत ही अलग विचार है।

    वास्तव में, कभी-कभी आपको इसकी आवश्यकता होती है/चाहती है। कभी-कभी आप नहीं करते हैं। यह आपके द्वारा हल की जा रही व्यावसायिक समस्या पर निर्भर करता है। बिल्कुल, आप अक्सर यह नहीं चाहते कि self पर एक मजबूत संदर्भ रखें, इस स्थिति में weakSelf पैटर्न सही समझ में आता है। लेकिन यह हमेशा मामला नहीं है।

    लेकिन मेरा मुद्दा यह है कि आपको एक मजबूत संदर्भ चक्र से बचने के लिए इस weakSelf पैटर्न (कम से कम इस dispatch_async परिदृश्य में) का पालन नहीं करना चाहिए। ऐसा कोई चक्र मौजूद नहीं है। जहां यह एक मुद्दा है जहां आपके पास ब्लॉक वैरिएबल है (उदा। कुछ completionHandler ब्लॉक)। उस स्थिति में, weakSelf पैटर्न महत्वपूर्ण है। लेकिन यहाँ नहीं।

  2. लेकिन चलिए उस दूसरे परिदृश्य के लिए विचार करें जिसमें आप self नहीं चाहते हैं। फिर एक सवाल है कि क्या आप प्रेषित कोड को पहले स्थान पर रखना चाहते हैं या नहीं। यदि नहीं, तो हो सकता है कि आपको जीसीडी के बजाय रद्द करने योग्य संचालन के साथ एक ऑपरेशन कतार का उपयोग करना चाहिए।

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

  3. लेकिन मान लीजिए कि (ए) आप वास्तव में प्रेषित कोड निष्पादित करना जारी रखना चाहते हैं, लेकिन (बी) आप self को बनाए रखना नहीं चाहते हैं। (यह एक दुर्लभ परिदृश्य की तरह प्रतीत होता है, लेकिन यह वह है जिसे आपने पूछा है, तो आइए इसका पीछा करें।) अंतिम प्रश्न यह है कि आपको strongSelf निर्माण की आवश्यकता है या नहीं। आपके मामले में, जहां आप केवल self की एक विधि को कॉल कर रहे हैं, आपको इस strongSelf निर्माण से परेशान करने की आवश्यकता नहीं है। यह केवल तभी महत्वपूर्ण है जब आप दिवालिया होने के लिए जा रहे हैं या अन्यथा दौड़ की स्थिति से बचने की जरूरत है। लेकिन, इस उदाहरण में, यह देखते हुए कि nil ऑब्जेक्ट को भेजा गया संदेश कुछ भी नहीं करता है, आपको तकनीकी रूप से अक्सर इस strongSelf निर्माण के बारे में चिंता करने की आवश्यकता नहीं होती है।

मुझे गलत मत समझो। weakSelf पैटर्न के साथ-साथ घोंसला strongSelf पैटर्न जो कभी-कभी इसके साथ होता है, के आस-पास की बाहों को प्राप्त करना अच्छा होता है। मैं बस सुझाव दे रहा हूं कि यह समझना अच्छा होगा कि इन पैटर्नों की वास्तव में आवश्यकता कब होती है। और मुझे लगता है कि एक रद्द करने योग्य NSOperation बनाम जीसीडी की पसंद अक्सर एक और अधिक महत्वपूर्ण है, लेकिन अक्सर अनदेखा, सवाल है।

3

ब्लॉक ढेर पर बनाए और संग्रहीत किए जाते हैं। तो जब ब्लॉक रिटर्न बनाया गया था तो ब्लॉक नष्ट हो जाएगा।

यदि कोई ब्लॉक एक आवृत्ति चर बन जाता है तो एआरसी ब्लॉक को ढेर से ढेर तक कॉपी करता है। आप कॉपी संदेश के साथ एक ब्लॉक को स्पष्ट रूप से कॉपी कर सकते हैं। आपका ब्लॉक अब एक ढेर-आधारित ब्लॉक के बजाय ढेर-आधारित ब्लॉक है। और आपको कुछ मेमोरी प्रबंधन मुद्दों से निपटना होगा। ब्लॉक स्वयं संदर्भित किसी भी ऑब्जेक्ट का एक मजबूत संदर्भ रखेगा। ब्लॉक के बाहर __weak पॉइंटर्स घोषित करें और फिर चक्र को बनाए रखने से बचने के लिए ब्लॉक के भीतर इस सूचक को संदर्भित करें।

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