6

के साथ उद्देश्य सी मेमोरी प्रबंधन अब मैं कुछ समय के लिए ब्लॉक का उपयोग कर रहा हूं, लेकिन मुझे लगता है कि एआरसी और गैर-एआरसी वातावरण दोनों में स्मृति प्रबंधन के बारे में मुझे कुछ याद आती है। मुझे लगता है कि गहरी समझ से मुझे कई मेमोरी लीक कम हो जाएंगी।ब्लॉक, एआरसी और गैर-एआरसी

AFNetworking किसी विशेष एप्लिकेशन में ब्लॉक का मेरा मुख्य उपयोग है। अधिकांश समय, एक ऑपरेशन के पूरा होने वाले हैंडलर के अंदर, मैं कुछ ऐसा करता हूं जैसे "[self.myArray addObject]"।

एआरसी और गैर-एआरसी सक्षम वातावरण दोनों में, "स्वयं" this article from Apple के अनुसार बनाए रखा जाएगा।

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

हालांकि, हाल ही में यह तब तक नहीं था जब तक मैंने एक चेतावनी पर ठोकर खाई जिसे मैं समझ नहीं पाया। मैं इस विशेष उदाहरण में एआरसी का उपयोग कर रहा हूं।

मैं दो उदाहरण चर कि पूरा होने और एक नेटवर्क आपरेशन

@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock; 
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock; 
@synthesize failureBlock = _failureBlock; 
@synthesize operation = _operation; 

कोड में कहीं की विफलता का संकेत है, मैं यह कर:

[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id 
                responseObject) { 
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}]; 
      _failureBlock(error); 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      NSLog(@"nothing"); 
     }]; 

Xcode लाइन है कि कॉल के बारे में शिकायत विफलता ब्लॉक, इस ब्लॉक में दृढ़ता से "कैप्चरिंग" स्वयं संदेश के साथ एक सतत चक्र में परिणाम होने की संभावना है। मेरा मानना ​​है कि एक्सकोड सही है: विफलता ब्लॉक स्वयं को बरकरार रखता है, और स्वयं ब्लॉक की अपनी प्रति रखता है, इसलिए दो में से कोई भी नहीं हटा दिया जाएगा

हालांकि, मेरे पास निम्नलिखित प्रश्न/टिप्पणियां हैं।

1) यदि मैं _failureBlock (त्रुटि) को "self.failureBlock (त्रुटि)" (उद्धरण के बिना) में बदलता हूं तो संकलक शिकायत करना बंद कर देता है। ऐसा क्यों है? क्या यह एक स्मृति रिसाव संकलक याद आती है?

2) आम तौर पर ब्लॉक का उपयोग करते समय एआरसी और गैर-एआरसी सक्षम वातावरण दोनों में ब्लॉक के साथ काम करने का सबसे अच्छा अभ्यास क्या है जो उदाहरण चर हैं? ऐसा लगता है कि AFNetworking में पूर्णता और विफलता ब्लॉक के मामले में, वे दो ब्लॉक उदाहरण चर नहीं हैं, इसलिए संभवतः वे ऊपर वर्णित चक्रों को बनाए रखने वाले चक्रों की श्रेणी में नहीं आते हैं। लेकिन AFNetworking में प्रगति ब्लॉक का उपयोग करते समय, ऊपर दिए गए चक्रों को बनाए रखने से बचने के लिए क्या किया जा सकता है?

मुझे एआरसी और गैर-एआरसी पर अन्य लोगों के विचारों को स्मृति प्रबंधन के साथ ब्लॉक और मुद्दों/समाधान के साथ सुनना अच्छा लगेगा। मुझे इन परिस्थितियों में त्रुटि-प्रवण लगता है और मुझे लगता है कि चीजों को साफ़ करने के लिए इस पर कुछ चर्चा आवश्यक है।

मुझे नहीं पता कि यह महत्वपूर्ण है, लेकिन मैं नवीनतम एलएलवीएम के साथ एक्सकोड 4.4 का उपयोग करता हूं।

उत्तर

6

1) अगर मैं _failureBlock (त्रुटि) करने के लिए "self.failureBlock (त्रुटि)" में बदल (उद्धरण के बिना) संकलक शिकायत बंद हो जाता है। ऐसा क्यों है? क्या यह एक मेमोरी रिसाव संकलक याद करता है?

रखरखाव चक्र दोनों मामलों में मौजूद है। आप iOS 5+ को लक्षित कर रहे हैं, तो आप स्वयं को एक कमजोर संदर्भ में पारित कर सकते हैं:

__weak MyClass *weakSelf; 
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}]; 
    if (weakSelf.failureBlock) weakSelf.failureBlock(error); 
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
    NSLog(@"nothing"); 
}]; 

अब स्वयं बनाकर नहीं रखे जाएंगे, और अगर यह पहले कॉलबैक शुरू हो जाती है पुनः आवंटित की जाती है, कॉलबैक एक नहीं- है सेशन। हालांकि, यह संभव है कि बैकबैक पृष्ठभूमि थ्रेड पर कॉल किए जाने पर इसे रद्द कर दिया जा सके, इसलिए यह पैटर्न कभी-कभी दुर्घटनाएं पैदा कर सकता है।

2) सामान्य तौर पर, क्या दोनों एआरसी और गैर एआरसी में ब्लॉक के साथ काम करने के लिए सबसे अच्छा अभ्यास सक्षम वातावरण जब ब्लॉक कि उदाहरण चर का उपयोग कर रहे है? ऐसा लगता है कि एफ़नेटवर्किंग में ब्लॉक के मामले में, उन दो ब्लॉक उदाहरण चर नहीं हैं इसलिए वे संभवतः ऊपर वर्णित चक्रों को बनाए रखने वाले चक्रों की श्रेणी में नहीं आते हैं जो मैं ऊपर वर्णित करता हूं। लेकिन AFNetworking में प्रगति ब्लॉक का उपयोग करते समय, ऊपर दिए गए चक्रों को बनाए रखने से बचने के लिए क्या किया जा सकता है?

ज्यादातर समय, मुझे लगता है कि it's better not to store blocks in instance variables। यदि आप अपनी कक्षा में किसी विधि से ब्लॉक को वापस कर देते हैं, तो आपके पास अभी भी एक सतत चक्र होगा, लेकिन यह तब तक मौजूद है जब ब्लॉक जारी होने के समय विधि लागू की जाती है। तो यह आपके निष्पादन को ब्लॉक निष्पादन के दौरान हटाए जाने से रोक देगा, लेकिन जब ब्लॉक जारी किया जाता है तो बनाए रखने का चक्र समाप्त होता है:

-(SFCompletionBlock)completionBlock { 
    return ^(AFHTTPRequestOperation *operation , id responseObject) { 
     [self doSomethingWithOperation:operation]; 
    }; 
} 

[self.operation setCompletionBlockWithSuccess:[self completionBlock] 
             failure:[self failureBlock] 
]; 
+0

इस उत्तर के लिए धन्यवाद। यह विचार के लिए बहुत खाना है। एक तरफ ध्यान दें, आपने कॉलबैक के बारे में क्या कहा और क्रैश के कारण पृष्ठभूमि थ्रेड सही है। हालांकि, ऐसी समस्याओं से बचने के लिए, मेरे मामले में मुख्य धागे में सभी समापन ब्लॉक को बुलाया जाता है।अन्य चीजों के लिए, चक्र को बनाए रखने के लिए "एक विधि से ब्लॉक को वापस करें" समाधान, जो एक पुन: प्रयोज्य घटक बनाने की मूल समस्या को हल नहीं करता है जहां कॉलर पूर्णता ब्लॉक का निर्णय लेगा। – csotiriou

+0

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

2

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

नहीं, self ब्लॉक बनने पर ब्लॉक द्वारा बनाए रखा जाता है।और जब ब्लॉक को हटा दिया जाता है तो इसे जारी किया जाता है।

मेरा मानना ​​है कि Xcode सही है: विफलता ब्लॉक को बरकरार रखे हुए स्वयं, और स्वयं ब्लॉक की अपनी एक प्रतिलिपि रखती है, तो दो में से कोई भी पुनः आवंटित की जाती दिया जाएगा।

self को बनाए रखने वाले प्रश्न में ब्लॉक setCompletionBlockWithSuccess पर पूरा हो गया है। self इस ब्लॉक के लिए एक संदर्भ नहीं है। इसके बजाय, self.operation (संभावित रूप से NSOperation का कुछ प्रकार) इसे निष्पादित करते समय ब्लॉक को बरकरार रखता है। तो अस्थायी रूप से एक चक्र है। हालांकि, जब ऑपरेशन निष्पादित किया जाता है, तो चक्र टूट जाएगा।

1) अगर मैं _failureBlock (त्रुटि) करने के लिए "self.failureBlock (त्रुटि)" में बदल (उद्धरण के बिना) संकलक शिकायत बंद हो जाता है। ऐसा क्यों है? क्या यह एक मेमोरी रिसाव संकलक याद करता है?

कोई अंतर नहीं होना चाहिए। self दोनों मामलों में कब्जा कर लिया गया है। कंपाइलर को बनाए रखने के चक्रों के सभी मामलों को पकड़ने की गारंटी नहीं है।