संक्षिप्त जवाब
self
सीधे पहुंचने के बजाय , आपको इसे अप्रत्यक्ष रूप से एक्सेस करना चाहिए, एक संदर्भ से जिसे बरकरार नहीं रखा जाएगा। यदि आप स्वचालित संदर्भ गणना (ARC) का उपयोग नहीं कर रहे हैं , तो आप यह कर सकते हैं:
__block MyDataProcessor *dp = self;
self.progressBlock = ^(CGFloat percentComplete) {
[dp.delegate myAPI:dp isProcessingWithProgress:percentComplete];
}
__block
कीवर्ड निशान चर कि ब्लॉक के अंदर संशोधित किया जा सकता है (हम कि नहीं कर रहे हैं), लेकिन यह भी तो वे अपने आप जब ब्लॉक बनाए रखा है बनाए रखा नहीं कर रहे हैं (जब तक आप एआरसी का उपयोग कर रहे हैं)। यदि आप ऐसा करते हैं, तो आपको यह सुनिश्चित करना चाहिए कि MyDataProcessor इंस्टेंस जारी होने के बाद ब्लॉक को निष्पादित करने की कोशिश करने के लिए और कुछ नहीं हो रहा है। (आपके कोड की संरचना को देखते हुए, यह समस्या नहीं होनी चाहिए।) के बारे में और पढ़ें__block
।
यदि आप एआरसी का उपयोग कर रहे हैं , तो __block
परिवर्तनों के संदर्भ और संदर्भ को बरकरार रखा जाएगा, जिस स्थिति में आपको इसके __weak
बजाय इसकी घोषणा करनी चाहिए ।
लंबा जवाब
मान लीजिए कि आपके पास इस तरह का कोड था:
self.progressBlock = ^(CGFloat percentComplete) {
[self.delegate processingWithProgress:percentComplete];
}
यहाँ समस्या यह है कि स्वयं ब्लॉक के संदर्भ को बरकरार रखे हुए है; इस बीच ब्लॉक को अपनी प्रतिनिधि संपत्ति लाने और प्रतिनिधि को एक विधि भेजने के लिए स्वयं के संदर्भ को बनाए रखना चाहिए। यदि आपके ऐप में मौजूद हर चीज इस ऑब्जेक्ट के लिए अपना संदर्भ जारी करती है, तो इसकी रिटन काउंट शून्य नहीं होगी (क्योंकि ब्लॉक इसे इंगित कर रहा है) और ब्लॉक कुछ भी गलत नहीं कर रहा है (क्योंकि ऑब्जेक्ट इसे इंगित कर रहा है) और इसलिए वस्तुओं की जोड़ी ढेर में लीक हो जाएगी, स्मृति पर कब्जा कर लेगी लेकिन हमेशा डिबगर के बिना पहुंच से बाहर होगी। दुखद, वास्तव में।
इसके बजाय यह मामला आसानी से तय किया जा सकता है:
id progressDelegate = self.delegate;
self.progressBlock = ^(CGFloat percentComplete) {
[progressDelegate processingWithProgress:percentComplete];
}
इस कोड में, स्वयं ब्लॉक को बनाए रख रहा है, ब्लॉक प्रतिनिधि को बनाए रख रहा है, और कोई चक्र नहीं हैं (यहां से दिखाई दे रहे हैं; प्रतिनिधि हमारी वस्तु को बनाए रख सकता है लेकिन यह अभी हमारे हाथ से बाहर है)। यह कोड उसी तरह से रिसाव का जोखिम नहीं उठाएगा, क्योंकि ब्लॉक करते समय प्रत्यायोजित संपत्ति का मूल्य कैप्चर किया जाता है, बजाय इसके निष्पादित होने पर देखा जाता है। एक दुष्प्रभाव यह है कि, यदि आप इस ब्लॉक के बनने के बाद प्रतिनिधि को बदलते हैं, तो ब्लॉक पुराने प्रतिनिधि को अपडेट संदेश भेजेगा। ऐसा होने की संभावना है या नहीं यह आपके आवेदन पर निर्भर करता है।
यहां तक कि अगर आप उस व्यवहार से शांत थे, तब भी आप अपने मामले में उस चाल का उपयोग नहीं कर सकते हैं:
self.dataProcessor.progress = ^(CGFloat percentComplete) {
[self.delegate myAPI:self isProcessingWithProgress:percentComplete];
};
यहां आप self
मेथड कॉल में सीधे प्रतिनिधि के पास जा रहे हैं , इसलिए आपको इसे वहां पहुंचाना होगा। यदि आपके पास ब्लॉक प्रकार की परिभाषा पर नियंत्रण है, तो सबसे अच्छी बात यह होगी कि प्रतिनिधि को पैरामीटर के रूप में ब्लॉक में पास करें:
self.dataProcessor.progress = ^(MyDataProcessor *dp, CGFloat percentComplete) {
[dp.delegate myAPI:dp isProcessingWithProgress:percentComplete];
};
यह समाधान बरकरार चक्र से बचा जाता है और हमेशा वर्तमान प्रतिनिधि को बुलाता है।
यदि आप ब्लॉक नहीं बदल सकते हैं, तो आप इससे निपट सकते हैं । एक चक्र बनाए रखने का कारण एक चेतावनी है, एक त्रुटि नहीं है, यह है कि वे आपके आवेदन के लिए जरूरी कयामत नहीं उड़ाते हैं। यदि MyDataProcessor
ऑपरेशन पूरा होने पर ब्लॉक जारी करने में सक्षम है, तो इससे पहले कि उसके माता-पिता इसे जारी करने की कोशिश करेंगे, चक्र टूट जाएगा और सब कुछ ठीक से साफ हो जाएगा। यदि आप इसके बारे में सुनिश्चित हो सकते हैं, तो #pragma
कोड के उस ब्लॉक के लिए चेतावनियों को दबाने के लिए उपयोग करना सही होगा । (या एक प्रति फ़ाइल संकलक ध्वज का उपयोग करें। लेकिन पूरी परियोजना के लिए चेतावनी को अक्षम न करें।)
आप ऊपर एक समान चाल का उपयोग कर सकते हैं, एक संदर्भ को कमजोर या अप्राप्य घोषित कर सकते हैं और ब्लॉक में इसका उपयोग कर सकते हैं। उदाहरण के लिए:
__weak MyDataProcessor *dp = self; // OK for iOS 5 only
__unsafe_unretained MyDataProcessor *dp = self; // OK for iOS 4.x and up
__block MyDataProcessor *dp = self; // OK if you aren't using ARC
self.progressBlock = ^(CGFloat percentComplete) {
[dp.delegate myAPI:dp isProcessingWithProgress:percentComplete];
}
उपरोक्त तीनों आपको परिणाम को बनाए रखने के बिना एक संदर्भ देंगे, हालांकि वे सभी थोड़ा अलग व्यवहार करते हैं: __weak
ऑब्जेक्ट जारी होने पर संदर्भ को शून्य करने की कोशिश करेंगे; __unsafe_unretained
अमान्य सूचक के साथ आपको छोड़ देगा; __block
वास्तव में अप्रत्यक्ष का एक और स्तर जोड़ देगा और आपको ब्लॉक के भीतर से संदर्भ के मूल्य को बदलने की अनुमति देगा (इस मामले में अप्रासंगिक, चूंकि dp
कहीं और उपयोग नहीं किया जाता है)।
जो सबसे अच्छा है वह इस बात पर निर्भर करेगा कि आप किस कोड को बदलने में सक्षम हैं और आप क्या नहीं कर सकते हैं। लेकिन उम्मीद है कि इसने आपको आगे बढ़ने के बारे में कुछ विचार दिए हैं।