23

के बिना ब्लॉक में [स्वयं कोई फ़ंक्शन] पास करना संभव है क्या यह स्वयं से __weak ऑब्जेक्ट के बिना ब्लॉक में [स्वयं किसी भी समारोह] को पास करना संभव है?बिना किसी __weak ऑब्जेक्ट (आईओएस 5 + एआरसी)

[UIView animateWithDuration:0.8 animations:^{ 
      //Do animationStuff 
     } completion:^(BOOL finished) { 
      [self anyFunction]; 
}]; 

आप एक बिना किसी चेतावनी के पूरा होने के ब्लॉक में [self anyFunction] पारित कर सकते हैं:

एक उदाहरण जैसा कि इस प्रणाली की रूपरेखा से मान्य कोड है। लेकिन अगर आप एक पूर्णता ब्लॉक के साथ अपनी खुद की विधि लिखते हैं, तो निम्न चेतावनी होती है: इस ब्लॉक में दृढ़ता से 'स्वयं' को कैप्चर करने से चक्र को बनाए रखने की संभावना है।

एक कामकाजी समाधान काफी सरल है (आईओएस 5 + एआरसी)। ब्लॉक घोषित करने से पहले:

[weakSelf anyFunction]; 

लेकिन, वापस मेरे सवाल का:: क्यों एक __weak उपयोग करने के लिए प्रणाली फ्रेमवर्क एपीआई में कोई जरूरत नहीं है

__weak MyClass *weakSelf = self; 

और पूरा ब्लॉक में आप कॉल करनी होगी ऑब्जेक्ट और किसी भी चेतावनी के बिना self का उपयोग करने के लिए। और ब्लॉक में __weak ऑब्जेक्ट की आवश्यकता के बिना किसी विधि को कैसे कार्यान्वित करें?

आपके प्रयास के लिए धन्यवाद।

उत्तर

53

त्रुटि जो फेंकने वाले ब्लॉक हैं वे हैं जहां आप अपने ब्लॉक को ऑब्जेक्ट्स कैप्चर करते हैं। उदाहरण के लिए

[object performBlock:^{ 
    [object performSomeAction]; // Will raise a warning 
}]; 

या

[self performBlock:^{ 
    [self doSomething]; // Will raise a warning 
}]; 

लेकिन

[self performBlock:^{ 
    [object doSomething]; // <-- No problem here 
}]; 

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

उदाहरण में आपने दिया है - आप क्लास विधि देख रहे हैं। आप ब्लॉक को UIView कक्षा पर कॉल कर रहे हैं, UIView ऑब्जेक्ट पर नहीं। एक कक्षा में इसके साथ कोई स्मृति नहीं है। और आप शायद इस फ़ंक्शन को नियंत्रक से कॉल कर रहे हैं, इसलिए self संदर्भ ब्लॉक द्वारा बनाए रखा जा रहा है, लेकिन कोई लूप नहीं है क्योंकि स्वयं ब्लॉक को बनाए नहीं रख रहा है।

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

+1

धन्यवाद, मेरा प्रश्न स्पष्ट किया गया है। मेरे मामले में ब्लॉक का स्वामित्व वाला ऑब्जेक्ट 'ivar' है, इसलिए आपको' self' 'की' __weak 'ऑब्जेक्ट का उपयोग करना होगा। लेकिन जब मैं उस कार्य में ऑब्जेक्ट घोषित करता हूं जहां ब्लॉक का उपयोग किया जाता है, तो 'स्वयं' को '__weak' ऑब्जेक्ट के बिना पास किया जा सकता है। यह समझ में आता है। एक बार फिर धन्यवाद। – andreschneider

+1

जो मैंने पाया वह है [self.ivar performBlock:^{[self doSomething]; }]; एक संकलक चेतावनी का कारण बन जाएगा, जबकि [स्वयं प्रदर्शनब्लॉक:^{[स्वयं doSomething]; }]; एक संकलक चेतावनी का कारण नहीं है। –

+0

शायद [स्वयं प्रदर्शनब्लॉक:^{[स्वयं doSomething];}]; प्रतिस्थापित किया जाना चाहिए [स्वयं प्रदर्शनब्लॉक:^{[स्वयं doSomething]; स्वयं = शून्य;}]; – dklt

14

कोड पर मुझे एआरसी के साथ या उसके बिना संभावित रूप से संकलित करने की आवश्यकता है, या नए कंपाइलरों के साथ या बिना, मैं निम्नलिखित करता हूं ... कार्यात्मक रूप से यह वही है जैसा आपने पहले सूचीबद्ध किया है, लेकिन यह__weak से भी बचाता है और यह भी रिहाई रिलीज चक्र से बचाता है:

// 
// FOR NON-ARC PROJECTS 
// 
__block __typeof__(self) bself = self; 
[someObject doThingWithBlock:^(id result){ 
    if (!bself) 
     return; 
    bself.thingWhich = result; 
}]; 

/// 
// FOR ARC PROJECTS 
// 
__weak MyClass *bself = self; 
[someObject doThingWithBlock:^(id result){ 
    if (!bself) 
     return; 
    bself.thingWhich = result; 
}]; 
+1

एआरसी के तहत, इससे एक सतत चक्र हो सकता है। ('__block' अर्थशास्त्र वस्तु को बनाए रखने के लिए बदल गया है।) –

+0

यह सही है। अब हम __weak MyClass * bself = self का उपयोग कर रहे हैं; –

+0

आर्क उदाहरण जोड़ा गया है, साथ ही साथ मेरी त्रुटि असीमित ब्लॉक के लिए हैंडलिंग। –