objective c - क्या एआरसी के तहत लक्ष्य-कार्य डिजाइन पैटर्न खराब अभ्यास बन गया?




objective-c ios (3)

सालों से मैं लक्ष्य-क्रिया नामक एक महान पैटर्न का पालन कर रहा हूं जो इस प्रकार है:

एक ऑब्जेक्ट कॉल करने के समय आने पर निर्दिष्ट लक्ष्य ऑब्जेक्ट पर एक निर्दिष्ट चयनकर्ता को कॉल करता है। यह कई अलग-अलग मामलों में बहुत उपयोगी है जहां आपको मनमाने ढंग से एक सरल कॉलबैक की आवश्यकता होती है।

यहां एक उदाहरण दिया गया है:

- (void)itemLoaded {
    [specifiedReceiver performSelector:specifiedSelector];
}

एआरसी के तहत अब यह पता चला है कि ऐसा कुछ अचानक अचानक खतरनाक हो गया।

एक्सकोड एक चेतावनी फेंकता है जो इस तरह जाता है:

प्रदर्शन चयनकर्ता रिसाव का कारण बन सकता है क्योंकि इसका चयनकर्ता अज्ञात है

निस्संदेह चयनकर्ता अज्ञात है क्योंकि लक्ष्य-क्रिया डिज़ाइन पैटर्न के हिस्से के रूप में आप कुछ चुनिंदा होने पर कॉल प्राप्त करने के लिए जो भी चयनकर्ता चाहते हैं उसे निर्दिष्ट कर सकते हैं।

इस चेतावनी के बारे में मुझे सबसे ज्यादा बग क्या है कि यह कहता है कि संभावित स्मृति रिसाव हो सकती है। मेरी समझ से एआरसी स्मृति प्रबंधन नियमों को झुका नहीं देता है बल्कि इसके बजाय सही स्थानों पर बनाए रखने / रिलीज / ऑटोरेलीज़ संदेशों को सम्मिलित करने के लिए स्वचालित रूप से स्वचालित करता है।

यहां ध्यान देने योग्य एक और बात: -परफॉर्म चयनकर्ता: एक id वापसी मूल्य है। एआरसी नामकरण सम्मेलनों के आवेदन के माध्यम से पता लगाने के लिए विधि हस्ताक्षर का विश्लेषण करता है यदि विधि +1 को गिनती वस्तु को बरकरार रखती है या नहीं। इस मामले में एआरसी को पता नहीं है कि चयनकर्ता एक- -newFooBar कारखाना है या बस एक -newFooBar कार्यकर्ता विधि (जिसे लगभग हमेशा लक्ष्य-कार्य के साथ मामला है) कहते हैं। दरअसल एआरसी को यह मानना ​​चाहिए था कि मुझे रिटर्न वैल्यू की उम्मीद नहीं है, और इसलिए किसी भी संभावित +1 को गिनती वापसी मूल्य को बरकरार रखने के बारे में भूल जाओ। उस दृष्टिकोण से इसे देखकर मैं देख सकता हूं कि एआरसी कहां से आ रहा है, लेकिन फिर भी अभ्यास में इसका वास्तव में क्या मतलब है इसके बारे में बहुत अनिश्चितता है।

क्या अब एआरसी के तहत इसका मतलब कुछ गलत हो सकता है जो एआरसी के बिना कभी नहीं होगा? मैं नहीं देखता कि यह स्मृति रिसाव कैसे उत्पन्न कर सकता है। क्या कोई ऐसी परिस्थितियों के उदाहरण दे सकता है जिसमें यह करना खतरनाक है, और उस मामले में वास्तव में एक रिसाव कैसे बनाया जाता है?

मैं वास्तव में इंटरनेट से बाहर निकल गया लेकिन मुझे यह बताते हुए कोई साइट नहीं मिली।


एआरसी चेतावनी फेंक रहा है क्योंकि यह गारंटी नहीं दे सकता कि चयनकर्ता उस वस्तु को नहीं बना रहा है जिसके बारे में पता नहीं है। आप सैद्धांतिक रूप से उस विधि से कुछ प्राप्त कर सकते हैं कि एआरसी संभाल नहीं सकता है:

id objectA = [someObject performSelector:@selector(createObjectA)];

शायद किसी दिन यह कर सकता है, लेकिन अभी यह नहीं कर सकता है। (ध्यान दें कि यह वस्तु को जानता है (यह एक आईडी नहीं है) यह इस चेतावनी को फेंक नहीं देता है)।

यदि आप किसी ऑब्जेक्ट को वापस प्राप्त किए बिना किसी विधि को निष्पादित करने का प्रयास कर रहे हैं, तो मैं objc_msgSend का उपयोग करने की सलाह देता हूं। लेकिन आपको अपनी कक्षा में शामिल होना होगा:

#include <objc/message.h>
objc_msgSend(someObject, action);

चेतावनी इस तरह पढ़नी चाहिए:

प्रदर्शन चयनकर्ता रिसाव का कारण बन सकता है क्योंकि इसका चयनकर्ता अज्ञात है। एआरसी को पता नहीं है कि लौटाए गए आईडी में +1 +1 गिनती है या नहीं, और इसलिए लौटाई गई वस्तु की स्मृति को सही ढंग से प्रबंधित नहीं किया जा सकता है।

दुर्भाग्य से, यह सिर्फ पहली वाक्य है।

अब समाधान:

यदि आपको एक -फॉर्मर चयनकर्ता विधि से वापसी मान प्राप्त होता है, तो आप इसे अनदेखा करने के अलावा कोड में चेतावनी के बारे में कुछ भी नहीं कर सकते हैं।

NSArray *linkedNodes = [startNode performSelector:nodesArrayAccessor];

आपकी सबसे अच्छी शर्त यह है:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSArray *linkedNodes = [startNode performSelector:nodesArrayAccessor];
#pragma clang diagnostic pop

मेरे प्रारंभिक प्रश्न में मामले के लिए वही है, जहां मैं वापसी मूल्य को पूरी तरह से अनदेखा करता हूं। एआरसी को यह देखने के लिए पर्याप्त बुद्धिमान होना चाहिए कि मुझे लौटाए गए आईडी की परवाह नहीं है, और इसलिए अज्ञात चयनकर्ता लगभग एक कारखाना, सुविधा कन्स्ट्रक्टर या जो कुछ भी नहीं होने की गारंटी देता है। दुर्भाग्यवश एआरसी नहीं है, इसलिए एक ही नियम लागू होता है। चेतावनी को अनदेखा करें।

परियोजना निर्माण सेटिंग्स में "अन्य चेतावनी झंडे" के तहत -Wno-arc-performSelector-leaks संकलक ध्वज सेट करके पूरे प्रोजेक्ट के लिए भी किया जा सकता है।

वैकल्पिक रूप से, आप प्रति-फ़ाइल आधार पर चेतावनी को दबा सकते हैं जब आप वांछित फ़ाइल के आगे दायीं तरफ अपने लक्ष्य> "बिल्ड चरण"> "संकलित स्रोत" के अंतर्गत उस ध्वज को जोड़ते हैं।

सभी तीन समाधान बहुत गन्दा IMHO हैं इसलिए मुझे उम्मीद है कि कोई बेहतर व्यक्ति के साथ आता है।


प्रदर्शन चयनकर्ता के साथ समस्या यह है कि एआरसी नहीं जानता कि चयनकर्ता क्या करेगा, करता है। निम्नलिखित को धयान मे रखते हुए:

id anotherObject1 = [someObject performSelector:@selector(copy)];
id anotherObject2 = [someObject performSelector:@selector(giveMeAnotherNonRetainedObject)];

अब, एआरसी कैसे जान सकता है कि पहली बार ऑब्जेक्ट को 1 की गिनती के साथ लौटाता है लेकिन दूसरा ऑब्जेक्ट देता है जो ऑटोरेलेज्ड होता है? (मैं सिर्फ giveMeAnotherNonRetainedObject नामक एक विधि को परिभाषित कर रहा हूं जो कुछ giveMeAnotherNonRetainedObject लौटाता है)। अगर यह किसी भी रिलीज में नहीं जोड़ा गया तो anotherObject1 यहां रिसाव होगा।

स्पष्ट रूप से मेरे उदाहरण में चयन करने वाले चयनकर्ता वास्तव में ज्ञात हैं, लेकिन कल्पना करें कि उन्हें रन टाइम पर चुना गया था। एआरसी वास्तव में यहां retain या सही release की सही संख्या में डालने का काम नहीं कर सका क्योंकि यह आसानी से नहीं जानता कि चयनकर्ता क्या करने जा रहा है। आप सही हैं कि एआरसी किसी भी नियम को झुका नहीं रहा है और यह सिर्फ आपके लिए सही मेमोरी प्रबंधन कॉल में जोड़ रहा है, लेकिन यह वही बात है जो यह यहां नहीं कर सकती है।

आप सही हैं कि तथ्य यह है कि आप रिटर्न वैल्यू को अनदेखा कर रहे हैं, इसका मतलब है कि यह ठीक होगा, लेकिन आम तौर पर एआरसी सिर्फ पिक्य और चेतावनी है। लेकिन मुझे लगता है कि यही कारण है कि यह एक चेतावनी है और कोई त्रुटि नहीं है।

संपादित करें:

यदि आप वास्तव में सुनिश्चित हैं कि आपका कोड ठीक है, तो आप इस तरह की चेतावनी को छिपा सकते हैं:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[specifiedReceiver performSelector:specifiedSelector];
#pragma clang diagnostic pop




automatic-ref-counting