एआरसी-सक्षम कोड में "ब्लॉक [एक वस्तु] को जोरदार ढंग से चेतावनी देना" इस चक्र को बनाए रखने की संभावना है


141

एआरसी सक्षम कोड में, ब्लॉक-आधारित एपीआई का उपयोग करते समय संभावित रिटेन साइकिल के बारे में चेतावनी को कैसे ठीक किया जाए?

चेतावनी:
Capturing 'request' strongly in this block is likely to lead to a retain cycle

कोड के इस स्निपेट द्वारा निर्मित:

ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.rawResponseData error:nil];
    // ...
    }];

चेतावनी को requestब्लॉक के अंदर ऑब्जेक्ट के उपयोग से जोड़ा जाता है ।


1
आपको शायद responseDataइसके बजाय का उपयोग करना चाहिए rawResponseData, ASIHTTPRequest प्रलेखन की जांच करें।
0

जवाबों:


165

खुद को जवाब देना:

प्रलेखन की मेरी समझ यह कहती है कि blockब्लॉक के अंदर उपयोग करने के बाद कीवर्ड और वेरिएबल को शून्य पर सेट करना ठीक होना चाहिए, लेकिन यह अभी भी चेतावनी दिखाता है।

__block ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
    request = nil;
// ....

    }];

अद्यतन: इसे ' _block' के बजाय '_ कमजोर' कीवर्ड के साथ काम करने के लिए मिला , और एक अस्थायी चर का उपयोग करके:

ASIHTTPRequest *_request = [[ASIHTTPRequest alloc] initWithURL:...
__weak ASIHTTPRequest *request = _request;

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
    // ...
    }];

अगर आप भी iOS 4 को टारगेट करना चाहते हैं, तो __unsafe_unretainedइसके बजाय इस्तेमाल करें __weak। समान व्यवहार, लेकिन ऑब्जेक्ट के नष्ट होने पर सूचक स्वचालित रूप से शून्य पर सेट होने के बजाय झूलता रहता है।


8
ARC डॉक्स के आधार पर, लगता है कि आपको ARC और ब्लॉक का उपयोग करते समय पहले जैसा व्यवहार करने के लिए __unsafe_unretain __block का उपयोग करने की आवश्यकता है।
हंटर

4
@ सीन क्लार्कहेस: जब मैं पहली दो पंक्तियों को मिलाता हूं, तो मुझे यह चेतावनी मिलती है: "कमजोर चर के लिए ऑब्जेक्ट को संरेखित करना; ऑब्जेक्ट असाइनमेंट के बाद जारी किया जाएगा"
Guillaume

1
प्रतिक्रिया के लिए @Guillaume धन्यवाद, कुछ मैंने कैसे अस्थायी चर की अनदेखी की, कोशिश की और चेतावनी चली गई है। क्या आप जानते हैं कि यह क्यों काम करता है? क्या यह सिर्फ चेतावनी को दबाने के लिए संकलक को बरगला रहा है या क्या चेतावनी वास्तव में मान्य नहीं है?
क्रिस वैगनर

2
मैंने एक अनुवर्ती प्रश्न पोस्ट किया है: stackoverflow.com/questions/8859649/…
barfoon

3
क्या कोई समझा सकता है कि आपको __block और __weak कीवर्ड की आवश्यकता क्यों है? मुझे लगता है कि एक बनाए रखने का चक्र है, लेकिन मैं इसे नहीं देखता हूं। और अस्थायी चर बनाने से समस्या कैसे ठीक होती है?
user798719

50

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

यह केवल अजीब है क्योंकि आप __ब्लॉक के साथ अनुरोध ऑब्जेक्ट को टैग कर रहे हैं ताकि यह स्वयं को संदर्भित कर सके। आप इसके साथ एक कमजोर संदर्भ बनाकर इसे ठीक कर सकते हैं ।

ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...];
__weak ASIHTTPRequest *wrequest = request;

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil];
    // ...
    }];

__weak ASIHTTPRequest * wrequest = अनुरोध; मेरे लिए काम नहीं किया। त्रुटि देने पर मैंने __ब्लॉक ASIHTTPRequest * blockRequest = request का उपयोग किया;
राम जी।

13

यह ब्लॉक में स्वयं को बनाए रखने के कारण होता है। ब्लॉक स्वयं से एक्सेस किया जाएगा, और स्वयं को ब्लॉक में संदर्भित किया जाता है। यह एक चक्र बनाए रखेगा।

इसे कमजोर रेफरेंस बनाकर हल करने का प्रयास करें self

__weak typeof(self) weakSelf = self;

operationManager = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

    [weakSelf requestFinishWithSucessResponseObject:responseObject withAFHTTPRequestOperation:operation andRequestType:eRequestType];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [weakSelf requestFinishWithFailureResponseObject:error withAFHTTPRequestOperation:operation andRequestType:eRequestType];
}];
[operationManager start];

यह सही उत्तर है और इसे इस तरह नोट किया जाना चाहिए
बेंजामिन

6

कुछ बार xcode संकलक को पहचानकर्ता के लिए समस्याएँ होती हैं कि वह चक्र को बनाए रखे, इसलिए यदि आप सुनिश्चित हैं कि आप पूर्णता को बनाए नहीं रख रहे हैं तो आप इस तरह संकलक ध्वज लगा सकते हैं:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"

-(void)someMethod {
}

1
कुछ लोग यह तर्क दे सकते हैं कि यह खराब डिज़ाइन है लेकिन मैं कभी-कभी स्वतंत्र वस्तुओं का निर्माण करता हूं जो स्मृति में तब तक लटका रहता है जब तक वे एक अतुल्यकालिक कार्य के साथ समाप्त नहीं हो जाते हैं। वे एक पूरा संपत्ति द्वारा बनाए रखे जाते हैं जिसमें एक मजबूत संदर्भ शामिल होता है, एक जानबूझकर बनाए रखने का चक्र। पूरा करने वाले बैल में self.completionBlock = nil होता है, जो पूरा होने पर रिलीज़ होता है और बनाए रखने के चक्र को तोड़ता है, जिससे ऑब्जेक्ट को कार्य पूरा होने के बाद मेमोरी से रिलीज़ किया जा सकता है। ऐसा करने पर होने वाली चेतावनियों को शांत करने में मदद करने के लिए आपका उत्तर उपयोगी है।
हाइपरस्पास्म

1
ईमानदार होने के लिए, एक के सही होने की संभावना और संकलक के गलत होने की संभावना बहुत कम है। इसलिए मैं कहूंगा कि चेतावनी को पार करना जोखिम भरा व्यवसाय है
मैक्स मैकलेओड

3

जब मैं गिलाउम द्वारा दिए गए समाधान की कोशिश करता हूं, तो सब कुछ डिबग मोड में ठीक है लेकिन यह रिलीज मोड में क्रैश हो जाता है।

ध्यान दें कि __weak का उपयोग न करें लेकिन __unsafe_unretain क्योंकि मेरा लक्ष्य iOS 4.3 है।

मेरा कोड क्रैश हो जाता है जब setCompletionBlock: ऑब्जेक्ट "अनुरोध" पर कॉल किया जाता है: अनुरोध को निपटाया गया था ...

इसलिए, यह समाधान डिबग और रिलीज़ मोड में काम करता है:

// Avoiding retain cycle :
// - ASIHttpRequest object is a strong property (crashs if local variable)
// - use of an __unsafe_unretained pointer towards self inside block code

self.request = [ASIHttpRequest initWithURL:...
__unsafe_unretained DataModel * dataModel = self;

[self.request setCompletionBlock:^
{
    [dataModel processResponseWithData:dataModel.request.receivedData];        
}];

दिलचस्प समाधान। क्या आपने यह पता लगाया कि यह रिलीज़ मोड में क्रैश क्यों होता है और डीबग में नहीं?
Valerio Santinelli


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.