2013-02-22 42 views
13

यदि मैं एक कमजोर वस्तु को संदेश भेजता हूं तो क्या होता है? क्या संदेश भेजने से ऑब्जेक्ट होता है और इसे वापस आने तक स्मृति में पकड़ता है?एक __weak ऑब्जेक्ट मैसेजिंग?

मैं इस पैटर्न के बारे में सोच रहा हूँ:

__weak MyObject *weakSelf = self; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [weakSelf doSomeAction]; 
}); 

मान लिया जाये कि weakSelf गैर शून्य जब संदेश भेजा जाता है, यह है, जबकि doSomeAction काम कर रहा है पुनः आवंटित की जाती हो सकता है या यह doSomeAction रिटर्न जब तक वैध रहेगा करने की गारंटी है?

उत्तर

18

Clang ARC documentation से: जब एक वस्तु lvalue पर एक lvalue करने वाली rvalue रूपांतरण प्रदर्शन

पढ़ना होता है।

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

एक कमजोर संदर्भ संदेश, चर पर एक lvalue करने वाली rvalue रूपांतरण है, जो कमजोर संदर्भ के मूल्य का मतलब रख लिया जाएगा और उसके बाद (मूल रूप से वर्तमान पूर्ण अभिव्यक्ति के अंत में जारी किया प्रदर्शन बयान)। यह मूल रूप से एक मजबूत चर को असाइन करने के बराबर है जिसका दायरा केवल वर्तमान कथन के लिए रहता है, और फिर उस मजबूत चर को संदेश भेजता है।

यहां लेआउट यह है कि यदि आप एक बार एक कमजोर चर संदेश भेजना चाहते हैं, और इसे फिर से स्पर्श न करें, और आप उस मामले में विधि के तर्कों का मूल्यांकन करने के दुष्प्रभावों की परवाह नहीं करते हैं जहां कमजोर संदर्भ समाप्त होता है nil ऊपर, फिर आगे बढ़ें और कमजोर संदर्भ सीधे संदेश भेजें। लेकिन यदि आपको कमजोर संदर्भ को दो बार (अलग-अलग कथन में) संदर्भित करने की आवश्यकता है, या तर्कों का मूल्यांकन करने के दुष्प्रभावों का कोई फर्क नहीं पड़ता है, तो आपको आगे बढ़ने से पहले एक मजबूत चर और गैर-nil के लिए परीक्षण करना चाहिए।

+0

यह मेरे लिए एक कार्यान्वयन quirk की तरह लगता है; मुझे संदेह है कि यह कहीं भी दस्तावेज/गारंटीकृत है। :) –

+0

@ रोब: स्टीवन ने कहा कि यह निश्चित रूप से एक कार्यान्वयन quirk है। कंपाइलर संभवतः 'objc_loadWeak()' का उपयोग करता है, जो 'objc_loadWeakRetained()' की बजाय मान को स्वत: करता है, जो नहीं करता है। आप इस व्यवहार पर भरोसा नहीं कर सकते, क्योंकि यह अनुकूलन स्तर या कंपाइलर के भविष्य के संस्करणों के साथ बदल सकता है। –

+0

एक अनुवर्ती प्रश्न: क्या ऐप्पल एलएलवीएम 5.0 में "__weak पॉइंटर्स को चेतावनी संदेश" चेतावनी प्रदान करता है? मुझे लगता है कि "एक __weak संदर्भ का बार-बार उपयोग करना" एक अलग चेतावनी है। जब तक कोई अनुकूलन न हो, जहां तर्कों का मूल्यांकन करने से पहले 'शून्य' जांच होती है (यानी, यह 'objc_msgSend' में नहीं होता है)? – Tommy

4

आप से पूछा:

मान लिया जाये कि weakSelf गैर nil जब संदेश भेजा जाता है, यह है, जबकि doSomeAction काम कर रहा है पुनः आवंटित की जाती हो सकता है या यह doSomeAction रिटर्न जब तक वैध रहेगा करने की गारंटी है?

हां, न केवल doSomeAction रिटर्न तक वैध रहता है, यह शेष ब्लॉक के लिए भी बनाए रखा जाता है। निम्नलिखित पर विचार करें:

- (void)dealloc 
{ 
    NSLog(@"%s", __FUNCTION__); 
} 

- (void)startBackgroundOperation 
{ 
    __weak MyObject * weakSelf = self; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [weakSelf doSomeAction]; 
     sleep(5); 
     [weakSelf doSomeAction2]; 
    }); 

    sleep(1); 
} 

- (void)doSomeAction 
{ 
    NSLog(@"%s", __FUNCTION__); 
} 

- (void)doSomeAction2 
{ 
    NSLog(@"%s", __FUNCTION__); 
} 

इस उदाहरण में, मुझे यकीन है कि वस्तु गुंजाइश जब ब्लॉक शुरू होता है में किया गया था, लेकिन यह doSomeAction और doSomeAction2 के बीच दायरे से बाहर हो जाते हैं, लेकिन ब्लॉक के लिए यह बनाए रखने के लिए प्रकट होता है ब्लॉक का समापन लेकिन अगर मैं doSomeAction के आविष्कार पर टिप्पणी करता हूं, तो weak संदर्भ nil है, जब तक यह doSomeAction2 पर आता है, जैसा कि आप उम्मीद करेंगे।


एक अलग रूप में के रूप में, WWDC 2011 - #322 - Objective-C Advancements In-Depth में, वे (वीडियो में के बारे में 27:00 मिनट) का कहना है, वे बताते हैं कि अगर आप weakSelf अपसंदर्भन रहे हैं, आप प्रेषण ब्लॉक के अंदर एक स्थानीय मजबूत संदर्भ होना चाहिए अपने आप को रेस स्थिति में की रक्षा के लिए, इस प्रकार:

__weak MyClass *weakSelf = self; 

dispatch_async(dispatch_get_main_queue(), ^{ 
    MyClass *strongSelf = weakSelf; 
    if (strongSelf) 
     [strongSelf->myView doSomeViewAction]; 
}); 

कि यह ब्लॉक की अवधि के लिए बनाए रखेगी (यह मानते हुए पहले से ही समय ब्लॉक मार डाला गया था द्वारा पुनः आवंटित की जाती नहीं गया था)।

+0

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

+0

@StevenFisher मैं एक कदम आगे जाऊंगा। एक कमजोर वस्तु को संदेश भेजना न केवल उस संदेश की अवधि, बल्कि पूरे ब्लॉक के लिए रखता है। लेकिन यदि ivars dereferencing, यह आपके लिए संदर्भ नहीं रखेगा, और इस प्रकार एक स्थानीय मजबूत संदर्भ की सलाह दी जाती है। मैंने तदनुसार अपना जवाब संशोधित कर दिया है। – Rob

+0

बहुत बेहतर, धन्यवाद। :) –