11

के साथ अपने स्वयं के समापन ब्लॉक में एनएसओपरेशन ऑब्जेक्ट को संदर्भित करना मुझे कुछ एनएसओपरेशन कोड को एआरसी में परिवर्तित करने में कठिनाई हो रही है। मेरा ऑपरेशन ऑब्जेक्ट एक समापन ब्लॉक का उपयोग करता है, जिसमें बदले में एक जीसीडी ब्लॉक होता है जो मुख्य थ्रेड पर यूआई अपडेट करता है। क्योंकि मैं अपने ऑपरेशन ऑब्जेक्ट को अपने स्वयं के समापन ब्लॉक के अंदर से संदर्भित करता हूं, इसलिए मैं मेमोरी लीक से बचने के लिए __weak पॉइंटर का उपयोग कर रहा हूं। हालांकि, मेरे कोड के चलते पॉइंटर पहले से ही शून्य हो गया है।एआरसी

मैंने इसे इस कोड नमूना में संकुचित कर दिया है। किसी को पता है कि मैं गलत कहां गया, और इसे पूरा करने का सही तरीका?

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init]; 
__weak NSOperationSubclass *weakOperation = operation; 

[operation setCompletionBlock:^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 

     // fails the check 
     NSAssert(weakOperation != nil, @"pointer is nil"); 

     ... 
    }); 
}]; 
+1

अच्छा, क्या गलत हुआ यह है कि एक कमजोर पॉइंटर स्वामित्व नहीं रखता है। यदि परिवर्तनीय (और वहां नहीं है) रखने के अलावा कुछ और नहीं है, तो इसे शुद्ध किया जा रहा है। क्या आप सुनिश्चित हैं कि यदि आप 'ऑपरेशन' का उपयोग करते हैं तो आपको रिसाव मिलती है? ऐसा लगता है कि पूरा होने पर ब्लॉक गायब हो जाना चाहिए, जिसे इसे जल्द ही कहा जाना चाहिए। (हालांकि यह मूर्ख हो सकता है।) –

+0

एआरसी संकलन समय पर इसके बारे में शिकायत कर रहा था। इसके बिना मैं सीधे ऑपरेशन पॉइंटर का उपयोग कर रहा था (और मुझे विश्वास नहीं है कि मैं स्मृति लीक कर रहा था)। –

+1

इसके साथ शुभकामनाएँ। मुझे लगता है कि छोड़ने और कुछ और करने से पहले मैंने कई घंटों तक इसके खिलाफ संघर्ष किया था। लेकिन यह थोड़ी देर हो गया है। :) –

उत्तर

10

मैं इस बारे में निश्चित नहीं हूँ, लेकिन यह करने के लिए सही तरीका ब्लॉक के अंत में सवाल में चर के लिए __block जोड़ने के लिए, और फिर इसे सेट नहीं के बराबर करने के लिए सुनिश्चित करने के लिए यह है कि संभवतः है का विमोचन किया। See this question.

आपका नया कोड इस तरह दिखेगा:

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init]; 
__block NSOperationSubclass *weakOperation = operation; 

[operation setCompletionBlock:^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 

     // fails the check 
     NSAssert(weakOperation != nil, @"pointer is nil"); 

     ... 
     weakOperation = nil; 
    }); 

}]; 
+3

आप सही हैं मुझे विश्वास है। धन्यवाद! –

14

एक अन्य विकल्प होगा:

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init]; 
__weak NSOperationSubclass *weakOperation = operation; 

[operation setCompletionBlock:^{ 
    NSOperationSubclass *strongOperation = weakOperation; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     assert(strongOperation != nil); 
     ... 
    }); 
}]; 

[operationQueue addOperation:operation]; 

मैं तुम्हें भी एक NSOperationQueue को आपरेशन वस्तु जोड़ने मान। उस स्थिति में, कतार एक संचालन को बरकरार रखती है। यह संभवतः इसे समापन ब्लॉक के निष्पादन के दौरान भी बनाए रखता है (हालांकि मुझे पूरा होने वाले ब्लॉक के बारे में आधिकारिक पुष्टि नहीं मिली है)।

लेकिन आपके पूरा होने के अंदर ब्लॉक एक और ब्लॉक बनाया गया है। उस ब्लॉक को कुछ समय बाद चलाया जाएगा, संभवतः एनएसओपरेशंस के समापन ब्लॉक के अंत में समाप्त होने के बाद। जब ऐसा होता है, operation कतार द्वारा जारी किया जाएगा और weakOperationnil होगा। लेकिन अगर हम ऑपरेशन के समापन ब्लॉक से उसी ऑब्जेक्ट का एक और मजबूत संदर्भ बनाते हैं, तो हम सुनिश्चित करेंगे कि operation दूसरा ब्लॉक चलने पर मौजूद होगा, और चक्र बनाए रखने से बचें क्योंकि हम ब्लॉक द्वारा operation चर को कैप्चर नहीं करते हैं। में Transitioning to ARC Release Notesउपयोग लाइफटाइम क्वालिफायर में पिछले कोड स्निपेट मजबूत संदर्भ चक्र से बचें खंड देखें

एप्पल इस उदाहरण प्रदान करता है।

+4

+1 यह सही उत्तर है।'एनएसओपरेशन' पूरा होने वाला ब्लॉक बरकरार रखता है, इसलिए इसे पूरा करने वाले ब्लॉक में कमजोर संदर्भ का उपयोग करना सुरक्षित है, क्योंकि यह अभी भी जीवित रहने की गारंटी है। हालांकि, ओपी की समस्या यह है कि वे इसे दूसरे ब्लॉक में उपयोग कर रहे हैं, जिसे बाद में निष्पादित किया जाता है, और कमजोर संदर्भ को जीवित रहने की गारंटी नहीं है। सही समाधान यह है कि दूसरे ब्लॉक में 'NSOperation' का एक मजबूत संदर्भ है – user102008

4

स्वीकृत उत्तर सही है।

बोली NSOperation documentation on @completionBlock से:

iOS 8 में और बाद में और ओएस एक्स v10.10 और बाद में, इस संपत्ति के लिए निर्धारित है लेकिन iOS 8/मैक ओएस 10.10 के रूप में आपरेशन weakify की कोई जरूरत नहीं है पूरा होने के बाद ब्लॉक करने के लिए ब्लॉक शुरू होता है।

पीट स्टीनबर्गर से this tweet भी देखें।