2011-10-13 14 views
28

एआरसी का उपयोग करते हुए 4.0 और 5.0 को लक्षित करने वाले आईओएस प्रोजेक्ट पर काम करना।एआरसी, ब्लॉक और चक्र बनाए रखें

ब्लॉक, एआरसी से संबंधित किसी मुद्दे में चलना और ब्लॉक के बाहर से किसी ऑब्जेक्ट का संदर्भ देना। यहाँ कुछ कोड है:

__block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
    [operation setCompletionBlock:^ { 
     if ([operation isCancelled]) { 
      return; 
     } 

... do stuff ... 

operation = nil; 
}]; 

इस मामले में, संकलक एक चेतावनी है कि ब्लॉक में 'आपरेशन' का उपयोग कर एक चक्र बनाए रखने के लिए नेतृत्व करने के लिए जा रहा है देता है। एआरसी के तहत, __block अब चर को बरकरार रखता है।

यदि मैं __unsafe_unretained जोड़ता हूं, तो संकलक तुरंत ऑब्जेक्ट को रिलीज़ करता है, इसलिए स्पष्ट रूप से यह काम नहीं करेगा।

मैं 4.0 को लक्षित कर रहा हूं इसलिए मैं __weak का उपयोग नहीं कर सकता।

मैं कुछ इस तरह कर रही करने की कोशिश की:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation; 

लेकिन जब weakOperation नहीं के बराबर नहीं है, यह से कोई भी गुण जब ब्लॉक के अंदर भर जाती है है।

ऊपर सूचीबद्ध परियोजना बाधाओं को देखते हुए इस स्थिति को संभालने का सबसे अच्छा तरीका क्या है?

उत्तर

23

प्रगति गारंटी मानते हुए, एक बनाए रखने वाला चक्र वही हो सकता है जो आप चाहते हैं। आप स्पष्ट रूप से ब्लॉक के अंत में बनाए रखने वाले चक्र को तोड़ते हैं, इसलिए यह स्थायी बनाए रखने चक्र नहीं है: जब ब्लॉक कहा जाता है, तो चक्र टूट जाता है।

यदि आपके पास ऑपरेशन को चारों ओर रखते हुए कुछ और है, तो आप किसी संदर्भ को __weak या __unsafe_unretained चर में संदर्भित कर सकते हैं और फिर अपने ब्लॉक के भीतर से इसका उपयोग कर सकते हैं। __block की आवश्यकता नहीं है - जब तक कि आप किसी कारण से ब्लॉक के दौरान चर के बाध्यकारी को बदलने की आवश्यकता नहीं है, तब तक चर को योग्य बनाएं; चूंकि आपके पास और तोड़ने के लिए एक सतत चक्र नहीं है, इसलिए आपको कमजोर चर में कुछ भी असाइन करने की आवश्यकता नहीं है।

+1

मुझे अपने दिमाग में 'कोई बरकरार चक्र' चीज नहीं मिली है, मैंने आपके द्वारा वर्णित तरीके से इसके बारे में भी सोचा नहीं था। ओह। अगला प्रश्न - संकलक चेतावनी को चुप करने का कोई तरीका? यह मुझे पागल ड्राइव करेगा। – Hunter

+1

क्लैंग उपयोगकर्ता के मैनुअल में ["प्रगति के माध्यम से डायग्नोस्टिक्स नियंत्रित करना]] (http://clang.llvm.org/docs/UsersManual.html#diagnostics_pragmas) देखें। आपको केवल यह पता लगाने की आवश्यकता होगी कि किस चेतावनी ध्वज को अनदेखा करना है। –

+4

यह '#pragma क्लैंग डायग्नोस्टिक अनदेखा "-वर्स-रिटेन-साइकिल" 'द्वारा, द्वारा किया गया है। –

1

यह समस्या Blocks, Operations, and Retain Cycles में कॉनरोड स्टॉल द्वारा वर्णित प्रतीत होता है, लेकिन उसके writeup में कुछ महत्वपूर्ण बिंदुओं याद करते हैं:

  • __block एमआरसी में कब्जा चर के लिए एक मजबूत संदर्भ से बचने का एप्पल के लिए सुझाया गया तरीका की तरह लग रहा मोड लेकिन एआरसी मोड में पूरी तरह से अनावश्यक है। इस मामले में, यह एआरसी मोड में पूरी तरह से अनावश्यक है; यह भी एमआरसी मोड में अनावश्यक है, हालांकि हल्का वजन वैकल्पिक हल भी बहुत कुछ वर्बोज़ है: void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; }
  • एआरसी मोड में, आप की जरूरत है दोनों एक मजबूत संदर्भ (ताकि आप इसे कतार में जोड़ सकते हैं) और एक कमजोर/unsafe_unretained संदर्भ

सरल समाधान इस तरह दिखता है:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
AFHTTPRequestOperation * __unsafe_unretained unretainedOperation = operation; 

[operation setCompletionBlock:^ { 
    if ([unretainedOperation isCancelled]) { 
    return; 
    } 
    ... do stuff ... 
}]; 

भले ही आप संदर्भ चक्र को तोड़ने, वहाँ ब्लॉक पहली जगह में AFHTTPRequestOperation बनाए रखने के लिए के लिए कोई कारण नहीं है (आपरेशन संभालने में ही जिंदा रहता है टी तक वह पूरा करने वाला हैंडलर पूरा करता है, जो हमेशा की गारंटी नहीं देता है, लेकिन आम तौर पर यह सच है और एआरसी द्वारा माना जाता है यदि इसे कॉल स्टैक के आगे self का उपयोग करने के लिए संदर्भित किया जाता है)।

सबसे अच्छा ठीकlatest AFNetworking है, जो एक तर्क के रूप ब्लॉक में आपरेशन गुजरता को अद्यतन करने के लिए प्रतीत होता है।

+0

__block पूरी तरह से अनावश्यक नहीं है। डिफ़ॉल्ट रूप से, ब्लॉक द्वारा बनाए गए सभी चर, इसके अंदर होंगे, इसलिए आप उनके मानों को नहीं बदल सकते हैं। यहां __block बचाव के लिए आता है। –

संबंधित मुद्दे