2012-04-25 14 views
18

एआरसी के साथ संकलन करते समय, विधि तर्क अक्सर विधि की शुरुआत में बनाए रखा जाता है और अंत में जारी किया जाता है। यह बरकरार/रिलीज जोड़ी अधूरा लगता है, और इस विचार के विपरीत है कि एआरसी "जिस कोड को आपने लिखा होगा वह उत्पन्न करता है"। उन अंधेरे में से कोई भी, पूर्व-एआरसी दिनों में सुरक्षित पक्ष पर रहने के लिए सभी विधि तर्कों पर अतिरिक्त रखरखाव/रिलीज नहीं किया गया था, है ना?एआरसी विधि तर्क क्यों बनाए रखता है?

पर विचार करें:

@interface Test : NSObject 
@end 

@implementation Test 

- (void)testARC:(NSString *)s 
{ 
    [s length]; // no extra retain/release here. 
} 

- (void)testARC2:(NSString *)s 
{ 
    // ARC inserts [s retain] 
    [s length]; 
    [s length]; 
    // ARC inserts [s release] 
} 

- (void)testARC3:(__unsafe_unretained NSString *)s 
{ 
    // no retain -- we used __unsafe_unretained 
    [s length]; 
    [s length]; 
    // no release -- we used __unsafe_unretained 
} 

@end 

जब रिलीज़ मोड, विधानसभा में Xcode 4.3.2 के साथ संकलित (जैसे कि मैं यह समझने में सक्षम हूँ) objc_retain और objc_release शुरू में और के अंत के लिए कॉल निहित दूसरी विधि क्या चल रहा है?

यह एक बड़ी समस्या नहीं है, लेकिन प्रोफ़ाइल प्रदर्शन-संवेदनशील कोड पर उपकरण का उपयोग करते समय यह अतिरिक्त बनाए रखने/रिलीज यातायात दिखाता है। ऐसा लगता है कि आप इस अतिरिक्त रखरखाव/रिलीज से बचने के लिए __unsafe_unretained के साथ विधि तर्कों को सजाने के लिए तैयार कर सकते हैं, जैसा कि मैंने तीसरे उदाहरण में किया है, लेकिन ऐसा करने से काफी घृणित लगता है।

+3

कोई विचार क्यों यह पहले उदाहरण में नहीं होता है? – Thilo

+0

आप हमेशा डिस्सेप्लोर सहायक दृश्य का उपयोग करके वास्तविक जेनरेट कोड देख सकते हैं। – Danra

उत्तर

17

ObjC-भाषा मेलिंग सूची से this reply देखें:

संकलक एक समारोह या विधि का स्मृति प्रबंधन के व्यवहार के बारे में कुछ भी पता नहीं है जब (और यह एक बहुत होता है), तो कंपाइलर को यह मानना ​​चाहिए:

1) कि फ़ंक्शन या विधि पूरी तरह से एप्लिकेशन के पूरे ऑब्जेक्ट ग्राफ़ को पुनर्व्यवस्थित या प्रतिस्थापित कर सकती है (शायद यह नहीं होगा, लेकिन यह हो सकता है)। 2) कि कॉलर मैन्युअल संदर्भ गिनती कोड हो सकता है, और इसलिए पैरामीटर में पारित होने का जीवनकाल वास्तविक रूप से पता नहीं है।

दिया गया # 1 और # 2; और यह देखते हुए कि एआरसी किसी ऑब्जेक्ट को को समय-समय पर हटाए जाने की अनुमति नहीं देता है, तो इन दो मान्यताओं में संकलक को ऑब्जेक्ट्स में पारित होने के लिए अधिक बार मजबूर करने के लिए मजबूर किया जाता है।

मुझे लगता है कि मुख्य समस्या यह इतना है कि एआरसी रक्षा कार्य और उन्हें बनाए रखने के लिए है कि अपने विधि के शरीर तर्कों को जन्म दे सकता जारी किया जा रहा है:

- (void) processItems 
{ 
    [self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]]; 
    [self doSomethingSillyWith:[items lastObject]]; 
} 

- (void) doSomethingSillyWith: (id) foo 
{ 
    [self setItems:nil]; 
    NSLog(@"%@", foo); // if ARC did not retain foo, you could be in trouble 
} 

कि यह भी कारण हो सकता है कि जब आप अपनी विधि में केवल एक कॉल करते हैं तो आपको अतिरिक्त बरकरार नहीं दिखता है।

+5

संक्षेप में, दूसरे उदाहरण में, '[s length]' के लिए पहली कॉल 's' को तब तक हटा दिया जा सकता है जब तक कि इसे पहले बनाए रखा न जाए, इसलिए दूसरा कॉल एक अस्तित्वहीन वस्तु पर हो सकता है। – JeremyP

+0

"कंपाइलर किसी फ़ंक्शन या विधि के मेमोरी प्रबंधन व्यवहार के बारे में कुछ भी नहीं जानता"। कोई सोचता है कि यह पता लगा सकता है (या ऐप्पल द्वारा बताया जा सकता है) कि एनएसएसटींग: लंबाई अच्छी तरह से व्यवहार की जाती है। क्या उदाहरण है जब संकलक के पास पर्याप्त उपयोगी जानकारी है? या यह वास्तव में * सभी * विधि कॉल के साथ होता है? – Thilo

+0

मुझे लगता है कि यह इसके लायक होने के लिए बहुत मुश्किल है। "अच्छी तरह से व्यवहार" शायद "स्थानीय चर से अलग कुछ भी जारी नहीं करता" के लिए उबाल जाएगा, और यह बनाने के लिए काफी मजबूत गारंटी है। विधि तर्कों पर अतिरिक्त बरकरार और रिलीज की लागत ज्यादातर लोगों के लिए प्रभावी रूप से शून्य होती है और जब यह वास्तव में आपको दर्द देती है, तो '__unsafe_unretained' मामले को हल करती है यदि आप जानते हैं कि आप क्या कर रहे हैं। – zoul

1

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

2

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

तो इस उदाहरण के बिना कि आप इस नए धागे को शुरू करने का इरादा रखते हैं, मैं एक निश्चित उत्तर नहीं दे सकता। सामान्य रूप से, हालांकि, आपको ठीक होना चाहिए।

2

यहां तक ​​कि आत्मा का जवाब सही है, यह थोड़ा गहरा की तुलना में यह होना चाहिए:

यह बनाए रखा है, क्योंकि पारित कर दिया संदर्भ एक मजबूत चर, पैरामीटर चर को सौंपा गया है। यह और केवल यही है कि बनाए रखने/रिलीज जोड़ी का कारण है। (पैरामीटर var को __weak पर सेट करें और क्या होता है?)

कोई इसे अनुकूलित कर सकता है? यह स्थानीय चरों पर हर रखरखाव/रिलीज जोड़े को अनुकूलित करने जैसा होगा, क्योंकि पैरामीटर स्थानीय चर हैं। यह किया जा सकता है, यदि संकलक विधि के अंदर छेद कोड को समझता है जिसमें भेजे गए सभी संदेश और कार्य कॉल शामिल हैं। यह लागू किया जा सकता है कि शायद ही कभी clang भी ऐसा करने की कोशिश नहीं करता है। (कल्पना कीजिए कि तर्क किसी समूह से संबंधित है (केवल) समूह से संबंधित है और समूह को हटा दिया गया है: व्यक्ति को भी हटा दिया जाएगा।)

और हाँ, एमआरसी में तर्क बनाए रखने के लिए नहीं था खतरनाक, लेकिन आम तौर पर डेवलपर्स अपने कोड को अच्छी तरह से जानते हैं, कि उन्होंने इसके बारे में सोचने के बिना बनाए रखा/रिलीज़ किया।

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