उद्देश्य-सी में शून्य करने के लिए एक संदेश भेजना


107

एक जावा डेवलपर के रूप में जो Apple के ऑब्जेक्टिव-सी 2.0 डॉक्यूमेंटेशन को पढ़ रहा है: मुझे आश्चर्य है कि " एनआईएल को संदेश भेजना " का अर्थ क्या है - अकेले जाने दें कि यह वास्तव में कैसे उपयोगी है। प्रलेखन से एक अंश लेना:

कोको में कई पैटर्न हैं जो इस तथ्य का लाभ उठाते हैं। संदेश से शून्य पर दिया गया मान भी मान्य हो सकता है:

  • यदि विधि किसी ऑब्जेक्ट, किसी पॉइंटर प्रकार, आकार के किसी पूर्णांक स्केलर को आकार के आकार (शून्य *) से कम या बराबर करती है, तो एक फ्लोट, एक डबल, एक लंबा डबल या एक लंबा लंबा, फिर शून्य रिटर्न के लिए भेजा गया एक संदेश 0 ।
  • यदि विधि एक संरचना लौटाती है, जैसा कि मैक ओएस एक्स एबीआई फंक्शन कॉल गाइड द्वारा परिभाषित किया गया है, तो रजिस्टरों में लौटाया जाना है, तो डेटा संरचना में प्रत्येक क्षेत्र के लिए शून्य रिटर्न 0.0 को भेजा गया एक संदेश है। अन्य संरचनात्मक डेटा प्रकार शून्य से नहीं भरे जाएंगे।
  • यदि विधि उपर्युक्त मान के अलावा कुछ भी लौटाती है तो शून्य पर भेजे गए संदेश का रिटर्न मान अपरिभाषित है।

क्या जावा ने मेरे मस्तिष्क को उपरोक्त स्पष्टीकरण देने में असमर्थ बना दिया है? या ऐसा कुछ है जो मुझे याद आ रहा है जो इसे ग्लास के रूप में स्पष्ट करेगा?

मुझे ऑब्जेक्टिव-सी में संदेशों / रिसीवरों का विचार मिलता है, मैं बस एक रिसीवर के बारे में उलझन में हूं जो कि होता है nil


2
मेरे पास एक जावा बैकग्राउंड भी था और मैं इस अच्छी सुविधा से शुरुआत में घबरा गया था, लेकिन अब मुझे यह पूरी तरह से प्यारा लगता है ;;
वैलेंटाइन रादु

1
धन्यवाद, यह एक बड़ा सवाल है। क्या आपने इसके माध्यम से लाभ देखा है? यह मुझे "बग नहीं, फीचर" के रूप में प्रभावित करता है। मुझे ऐसे कीड़े मिलते रहते हैं जहाँ जावा मुझे एक अपवाद के साथ थप्पड़ मारता है, इसलिए मुझे पता था कि समस्या कहाँ थी। मैं एक या दो तुच्छ कोड यहाँ और वहाँ बचाने के लिए अशक्त सूचक अपवाद का व्यापार करने के लिए खुश नहीं हूँ।
मकीज ट्राइबेलो

जवाबों:


92

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

void foo(ArrayList list)
{
    for(int i = 0; i < list.size(); ++i){
        System.out.println(list.get(i).toString());
    }
}

अब, यदि आप उस विधि को इस तरह कहते हैं: someObject.foo (NULL); जब आप सूची में प्रवेश करने की कोशिश करते हैं, तो कॉल करने के लिए कॉल करने के लिए संभवत: एक NullPointerException प्राप्त करने जा रहे हैं। अब, आप शायद कभी भी इस तरह के NULL मान के साथ someObject.foo (NULL) कॉल नहीं करेंगे। हालाँकि, आप अपने ArrayList को एक विधि से प्राप्त कर सकते हैं जो NULL को लौटाता है यदि यह ArrayList को someObject.foo (otherObject.getArrayList ()) को उत्पन्न करने में कुछ त्रुटि में चलता है;

यदि आप कुछ इस तरह से करते हैं, तो निश्चित रूप से, आपको समस्याएँ भी होंगी:

ArrayList list = NULL;
list.size();

अब, Objective-C में, हमारे पास समान विधि है:

- (void)foo:(NSArray*)anArray
{
    int i;
    for(i = 0; i < [anArray count]; ++i){
        NSLog(@"%@", [[anArray objectAtIndex:i] stringValue];
    }
}

अब, अगर हमारे पास निम्नलिखित कोड है:

[someObject foo:nil];

हमारे पास वही स्थिति है जिसमें जावा एक NullPointerException का उत्पादन करेगा। NIL ऑब्जेक्ट को पहले [AArray count] पर एक्सेस किया जाएगा, हालांकि, NullPointerException को फेंकने के बजाय, Objective-C ऊपर दिए गए नियमों के अनुसार केवल 0 वापस करेगा, इसलिए लूप नहीं चलेगा। हालाँकि, अगर हम लूप को एक निर्धारित संख्या में चलाने के लिए सेट करते हैं, तो हम पहले [aArray objectAtIndex: i] पर एक एरियर के लिए एक संदेश भेज रहे हैं; यह 0 भी लौटेगा, लेकिन चूंकि objectAtIndex: एक पॉइंटर लौटाता है, और 0 के लिए एक पॉइंटर nil / NULL है, लूप के माध्यम से NSLog को हर बार nil पास किया जाएगा। (हालांकि NSLog एक फ़ंक्शन है और एक विधि नहीं है, यह एक शून्य NSString पास होने पर (शून्य) प्रिंट करता है।

कुछ मामलों में यह NullPointerException के लिए अच्छा है, क्योंकि आप तुरंत बता सकते हैं कि प्रोग्राम में कुछ गड़बड़ है, लेकिन जब तक आप अपवाद को पकड़ नहीं लेते, प्रोग्राम क्रैश हो जाएगा। (सी में, इस तरह से NULL को रोकने की कोशिश करने से प्रोग्राम क्रैश हो जाता है।) ऑब्जेक्टिव-सी में, इसके बजाय यह संभवतः गलत रन-टाइम व्यवहार का कारण बनता है। हालाँकि, यदि आपके पास एक ऐसी विधि है जो 0 / nil / NULL / एक शून्य संरचना को लौटाती है तो वह नहीं टूटती है, तो यह आपको यह सुनिश्चित करने के लिए जाँचने से रोकता है कि वस्तु या पैरामीटर शून्य हैं।


33
यह शायद उल्लेखनीय है कि यह व्यवहार पिछले कुछ दशकों में उद्देश्य-सी समुदाय में बहुत बहस का विषय रहा है। "सुरक्षा" और "सुविधा" के बीच के व्यापार का मूल्यांकन अलग-अलग लोगों द्वारा अलग-अलग तरीके से किया जाता है।
मार्क बेस्सी

3
व्यवहार में, संदेश को पास करने और कैसे उद्देश्य-सी काम करता है, विशेष रूप से एआरसी में नए कमजोर संकेत सुविधा के बीच समरूपता है। कमजोर बिंदु स्वतः शून्य हो जाते हैं। इसलिए आप API डिज़ाइन करें ताकि वह 0 / nil / NIL / NULL आदि का जवाब दे सके
Cthutu

1
मुझे लगता है कि अगर आप ऐसा करते हैं तो myObject->iVarचाहे वह C के साथ या बिना वस्तुओं के दुर्घटनाग्रस्त हो जाए । (सॉरी टू ग्रेवेडिग।)
11684

3
@ 11684 यह सही है, लेकिन ->अब एक Objective-C ऑपरेशन नहीं है, लेकिन बहुत ही सामान्य C-ism है।
बबूम

1
हाल ही में OSX जड़ शोषण / छिपा पिछले दरवाजे एपीआई Obj सी के शून्य मैसेजिंग की वजह से सभी उपयोगकर्ताओं (केवल व्यवस्थापक) के लिए सुलभ है।
dcow


41

अन्य सभी पोस्ट सही हैं, लेकिन हो सकता है कि यह अवधारणा यहां महत्वपूर्ण है।

ऑब्जेक्टिव-सी मेथड कॉल में, कोई भी ऑब्जेक्ट रेफरेंस जो किसी चयनकर्ता को स्वीकार कर सकता है, उस चयनकर्ता के लिए एक वैध लक्ष्य है।

यह एक बहुत बचाता है "X का लक्ष्य ऑब्जेक्ट है?" कोड - जब तक प्राप्त करने वाला ऑब्जेक्ट चयनकर्ता को लागू करता है, तब तक यह बिल्कुल कोई फर्क नहीं पड़ता है कि यह किस वर्ग का है! nilएक NSObject है जो किसी भी चयनकर्ता को स्वीकार करता है - यह सिर्फ कुछ भी नहीं करता है। यह बहुत सारे "चेक फॉर नील" को समाप्त कर देता है, यदि सही है तो कोड को संदेश न भेजें। ("यदि यह इसे स्वीकार करता है, तो यह इसे लागू करता है" अवधारणा यह भी है कि क्या आप प्रोटोकॉल बनाने की अनुमति देते हैं, जो कि जावा इंटरफेस की तरह थोड़े थोड़े हैं: एक घोषणा कि यदि कोई वर्ग बताए गए तरीकों को लागू करता है, तो यह प्रोटोकॉल के अनुरूप है।

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

डाउनवोटर्स के लिए स्पष्ट करना: आप सोच सकते हैं कि यह जाने का एक अच्छा तरीका नहीं है, लेकिन यह है कि भाषा कैसे लागू की जाती है, और यह उद्देश्य-सी में अनुशंसित प्रोग्रामिंग मुहावरा है (स्टैनफोर्ड iPhone प्रोग्रामिंग व्याख्यान देखें)।


17

इसका क्या मतलब है कि जब objc_msgSend को nil पॉइंटर पर बुलाया जाता है, तो रनटाइम एक त्रुटि उत्पन्न नहीं करता है; इसके बजाय यह कुछ (अक्सर उपयोगी) मूल्य देता है। ऐसे संदेश जिनका साइड इफेक्ट हो सकता है, कुछ नहीं करते।

यह उपयोगी है क्योंकि अधिकांश डिफ़ॉल्ट मान एक त्रुटि से अधिक उपयुक्त हैं। उदाहरण के लिए:

[someNullNSArrayReference count] => 0

यानी, शून्य खाली सरणी प्रतीत होता है। एक nil NSView संदर्भ छुपाने से कुछ नहीं होता है। काम, एह?


12

प्रलेखन से उद्धरण में, दो अलग-अलग अवधारणाएं हैं - शायद यह बेहतर हो सकता है यदि प्रलेखन ने इसे और अधिक स्पष्ट किया:

कोको में कई पैटर्न हैं जो इस तथ्य का लाभ उठाते हैं।

संदेश से शून्य पर दिया गया मान भी मान्य हो सकता है:

पूर्व शायद यहां अधिक प्रासंगिक है: आमतौर पर nilकोड को अधिक सरल बनाने के लिए संदेश भेजने में सक्षम होने के नाते - आपको हर जगह अशक्त मानों की जांच करने की आवश्यकता नहीं है। विहित उदाहरण शायद अभिगम विधि है:

- (void)setValue:(MyClass *)newValue {
    if (value != newValue) { 
        [value release];
        value = [newValue retain];
    }
}

यदि संदेश भेजना nilमान्य नहीं थे, तो यह विधि अधिक जटिल होगी - आपको यह सुनिश्चित करने के लिए दो अतिरिक्त चेक करने होंगे valueऔर उन्हें संदेश भेजने से पहले newValueनहीं होना nilचाहिए।

उत्तरार्द्ध बिंदु (जो मान किसी संदेश से लौटे nilहैं वे भी आमतौर पर मान्य हैं), हालांकि, पूर्व में एक गुणक प्रभाव जोड़ता है। उदाहरण के लिए:

if ([myArray count] > 0) {
    // do something...
}

इस कोड को फिर से nilमानों के लिए जांच की आवश्यकता नहीं है , और स्वाभाविक रूप से बहती है ...

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


12

से ग्रेग पार्कर की साइट :

यदि LLVM कंपाइलर 3.0 (Xcode 4.2) या बाद में चल रहा है

वापसी प्रकार के साथ शून्य करने के लिए संदेश | वापसी
64 बिट तक के इंटीजर | 0
फ्लोटिंग-पॉइंट टू लॉन्ग डबल | 0.0
संकेत | शून्य
संरचनाएं | {0}
कोई भी _Complex प्रकार | {0, 0}

9

इसका मतलब अक्सर सुरक्षा के लिए हर जगह नील वस्तुओं की जांच नहीं करना है - विशेष रूप से:

[someVariable release];

या, जैसा कि उल्लेख किया गया है, विभिन्न गणना और लंबाई विधियां सभी 0 वापस आती हैं जब आपको एक शून्य मान मिलता है, इसलिए आपको सभी के लिए शून्य के लिए अतिरिक्त चेक जोड़ने की आवश्यकता नहीं है:

if ( [myString length] > 0 )

या यह:

return [myArray count]; // say for number of rows in a table

इस बात को ध्यान में रखें कि सिक्के के दूसरे हिस्से में कीड़े होने की संभावना है जैसे "अगर ([myString लंबाई] == 1)"
हैफिंच

वह बग कैसे है? [myString की लंबाई] शून्य (nil) लौटाता है यदि myString शून्य है ... मुझे लगता है कि एक मुद्दा एक मुद्दा हो सकता है [myView फ्रेम] जो मुझे लगता है कि आपको कुछ निराला दे सकता है यदि myView nil है।
केंडल हेल्मसटेटर गेलनर

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

6

"रिसीवर शून्य होने" के बारे में मत सोचो; मैं सहमत हूं, यह बहुत अजीब है। यदि आप शून्य पर संदेश भेज रहे हैं, तो कोई रिसीवर नहीं है। आप सिर्फ कुछ नहीं करने के लिए एक संदेश भेज रहे हैं।

इससे कैसे निपटें कि जावा और उद्देश्य-सी के बीच एक दार्शनिक अंतर है: जावा में, यह एक त्रुटि है; ऑब्जेक्टिव-सी में, यह एक नो-ऑप है।


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

6

ObjC संदेश जो शून्य पर भेजे जाते हैं और जिनके रिटर्न मान साइज़ोफ (void *) से बड़े आकार के होते हैं, PowerPC प्रोसेसर पर अपरिभाषित मान उत्पन्न करते हैं। इसके अलावा, ये संदेश उन अपरिभाषित मूल्यों का कारण बनते हैं, जो उन क्षेत्रों में लौटाए जाते हैं जिनका आकार इंटेल प्रोसेसर पर 8 बाइट्स से बड़ा होता है। विंसेंट गेबल ने अपने ब्लॉग पोस्ट में इसका अच्छी तरह से वर्णन किया है


6

मुझे नहीं लगता कि किसी भी अन्य उत्तर ने यह स्पष्ट रूप से उल्लेख किया है: यदि आप जावा के लिए उपयोग किए जाते हैं, तो आपको ध्यान रखना चाहिए कि मैक ओएस एक्स पर ऑब्जेक्टिव-सी में अपवाद हैंडलिंग समर्थन है, यह एक वैकल्पिक भाषा सुविधा है जो कि हो सकती है संकलक ध्वज के साथ चालू / बंद। मेरा अनुमान है कि "संदेश भेजने का यह संदेश nilसुरक्षित है" भाषा में अपवाद हैंडलिंग समर्थन को शामिल करने से पहले होता है और यह एक समान लक्ष्य को ध्यान में रखते हुए किया गया था: nilत्रुटियों को इंगित करने के लिए तरीके वापस आ सकते हैं, और nilआमतौर पर संदेश भेजने के बाद सेnilबदले में, यह त्रुटि संकेत को आपके कोड के माध्यम से प्रचारित करने की अनुमति देता है ताकि आपको हर एक संदेश पर इसके लिए जाँच न करनी पड़े। आपको इसके लिए केवल उन बिंदुओं पर जांच करनी होगी जहां यह मायने रखता है। मुझे व्यक्तिगत रूप से लगता है कि अपवाद प्रचार और हैंडलिंग इस लक्ष्य को संबोधित करने का एक बेहतर तरीका है, लेकिन हर कोई इससे सहमत नहीं हो सकता है। (दूसरी ओर, मैं उदाहरण के लिए नहीं जावा की आवश्यकता है जैसे आप घोषित करने के लिए क्या अपवाद एक विधि फेंक कर सकते हैं, जो अक्सर आप के लिए बलों होने पर ऐसा वाक्य रचना अपने कोड भर प्रचार अपवाद घोषणाओं, लेकिन है कि एक और चर्चा है।)

मैंने एक समान पोस्ट किया है, लेकिन अब, संबंधित प्रश्न का उत्तर है "क्या यह दावा है कि प्रत्येक वस्तु निर्माण उद्देश्य सी में आवश्यक है?" यदि आप अधिक जानकारी चाहते हैं।


मैंने इसके बारे में कभी नहीं सोचा था। यह एक बहुत ही सुविधाजनक सुविधा प्रतीत होती है।
mk12

2
अच्छा अनुमान है, लेकिन ऐतिहासिक रूप से गलत है कि निर्णय क्यों किया गया था। अपवाद हैंडलिंग शुरुआत से ही भाषा में मौजूद थी, हालांकि आधुनिक मुहावरे की तुलना में मूल अपवाद हैंडलर काफी आदिम थे। निल-ईट्स-संदेश स्मालटाकल में निल वस्तु के वैकल्पिक व्यवहार से प्राप्त एक जागरूक डिजाइन विकल्प था । जब मूल NeXTSTEP API को डिजाइन किया गया था, तो विधि-निर्धारण काफी सामान्य था और एक nilबार में शॉर्ट-सर्किट का उपयोग करने के लिए एक एनओ-ऑप में चेन को लौटाया जाता था।
बीबीम

2

C आदिम मूल्यों के लिए 0 के रूप में कुछ भी नहीं दर्शाता है, और पॉइंटर्स के लिए NULL (जो एक पॉइंटर संदर्भ में 0 के बराबर है)।

उद्देश्य-सी शून्य को जोड़कर सी के प्रतिनिधित्व पर बनाता है। शून्य कुछ भी नहीं करने के लिए एक वस्तु सूचक है। यद्यपि NULL से शब्दार्थ भिन्न है, वे तकनीकी रूप से एक दूसरे के समतुल्य हैं।

नव-आबंटित NSObjects अपनी सामग्री 0. के साथ सेट की गई सामग्री के साथ जीवन शुरू करते हैं। इसका मतलब है कि अन्य ऑब्जेक्ट्स के लिए ऑब्जेक्ट को इंगित करने वाले सभी उपकरण शून्य के रूप में शुरू होते हैं, इसलिए, उदाहरण के लिए, स्वयं को सेट करना अनावश्यक है।

हालांकि, नील का सबसे उल्लेखनीय व्यवहार यह है कि इसमें भेजे गए संदेश हो सकते हैं।

अन्य भाषाओं में, जैसे C ++ (या Java), यह आपके प्रोग्राम को क्रैश कर देगा, लेकिन ऑब्जेक्टिव-सी में, nil पर एक विधि लागू करने से शून्य मान प्राप्त होता है। यह अभिव्यक्ति को बहुत सरल करता है, क्योंकि यह कुछ भी करने से पहले नील की जांच करने की आवश्यकता को कम करता है:

// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }

// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }

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

स्रोत: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (शून्य पर संदेश)।

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