2010-02-03 38 views
46

उद्देश्य-सी में, [object doSomething] क्यों? क्या यह [*object doSomething] नहीं होगा क्योंकि आप ऑब्जेक्ट पर कोई विधि बुला रहे हैं? जिसका मतलब है कि आपको पॉइंटर को हटाना चाहिए?क्यों [वस्तु कुछ करते हैं] और नहीं [* वस्तु कुछ करते हैं]?

उत्तर

110

उत्तर उद्देश्य-सी की सी जड़ों पर वापस आता है। उद्देश्य-सी मूल रूप से सी के लिए एक कंपाइलर प्री-प्रोसेसर के रूप में लिखा गया था, यही है, उद्देश्य-सी को संकलित नहीं किया गया था क्योंकि इसे सीधे सी में परिवर्तित किया गया था और फिर संकलित किया गया था।

id प्रकार की परिभाषा से शुरू करें।

typedef struct objc_object { 
    Class isa; 
} *id; 

है यही कारण है, एक id एक संरचना जिनकी पहली फ़ील्ड प्रकार कक्षा (जो, अपने आप में, एक संरचना है कि एक वर्ग को परिभाषित करता करने के लिए एक सूचक है) की है करने के लिए एक सूचक है: के रूप में यह घोषित किया जाता है। अब, NSObject पर विचार करें:

@interface NSObject <NSObject> { 
    Class isa; 
} 

ध्यान दें कि NSObject के लेआउट और प्रकार के लेआउट id द्वारा की ओर इशारा समान हैं। ऐसा इसलिए है क्योंकि, हकीकत में, उद्देश्य-सी ऑब्जेक्ट का एक उदाहरण वास्तव में एक संरचना के लिए एक सूचक है जिसका पहला क्षेत्र - हमेशा एक सूचक - उस वर्ग के लिए अंक जिसमें उस उदाहरण के तरीकों को शामिल किया गया है (कुछ अन्य मेटाडेटा के साथ)।

जब आप एनएसओब्जेक्ट को उप-वर्गीकृत करते हैं और कुछ उद्देश्यों और प्रयोजनों के लिए कुछ आवृत्ति चर जोड़ते हैं, तो बस एक नई सी संरचना बनाते हैं जिसमें आपके इंस्टॉलेशन वैरिएबल होते हैं जो सभी सुपरक्लास के लिए आवृत्ति चर के लिए स्लॉट पर संयोजित उस संरचना में स्लॉट के रूप में होते हैं। (आधुनिक रनटाइम थोड़ा अलग-अलग काम करता है ताकि एक सुपरक्लास में सभी उप-वर्गों को पुन: संकलित करने की आवश्यकता के बिना ivars संलग्न किया जा सके)।

(- कोई ObjC शामिल एक साधारण सी संरचना NSRect जा रहा है)
NSRect foo; 
NSRect *bar; 

:

अब, इन दो चर के बीच अंतर पर विचार करें। foo स्टैक पर स्टोरेज के साथ बनाया गया है। स्टैक फ्रेम बंद होने के बाद यह जीवित नहीं रहेगा, लेकिन आपको किसी भी स्मृति को मुक्त करने की आवश्यकता नहीं है। bar एक NSRect संरचना का संदर्भ है जो सबसे अधिक संभावना है, malloc() का उपयोग करके ढेर पर बनाया गया था। ढेर आधारित वस्तुओं की तर्ज पर कुछ कहने ऑब्जेक्टिव-सी में अनुमति नहीं है

NSArray foo; 
NSArray *bar; 

संकलक के बारे में पहली शिकायत,:

आप कहते हैं की कोशिश करते हैं। दूसरे शब्दों में, सभी उद्देश्य-सी वस्तुओं को ढेर से आवंटित किया जाना चाहिए (अधिक या कम - एक या दो अपवाद हैं, लेकिन वे इस चर्चा के लिए तुलनात्मक रूप से गूढ़ हैं) और परिणामस्वरूप, आप हमेशा संदर्भ देखें ढेर पर कहा वस्तु के पते के माध्यम से एक वस्तु के लिए; आप ऑब्जेक्ट्स के पॉइंटर्स के साथ हमेशा काम कर रहे हैं (और id प्रकार वास्तव में किसी भी पुराने ऑब्जेक्ट के लिए एक सूचक है)।

भाषा की सी पूर्वप्रक्रमक जड़ों को वापस हो रही है, आप उदाहरण के लिए सी के एक बराबर लाइन के लिए हर विधि कॉल अनुवाद कर सकते हैं, कोड की निम्न दो पंक्तियों समान हैं:

[myArray objectAtIndex: 42]; 
objc_msgSend(myArray, @selector(objectAtIndex:), 42); 

इसी तरह, एक विधि इस तरह की घोषणा की:

- (id) objectAtIndex: (NSUInteger) a; 

सी समारोह के बराबर है इस तरह की घोषणा की:

id object_at_index(id self, SEL _cmd, NSUInteger a); 
,210

और, objc_msgSend() को देखते हुए, पहला तर्क प्रकार id का घोषित किया जाता है:

OBJC_EXPORT id objc_msgSend(id self, SEL op, ...); 

और वह यही कारण है कि आप एक विधि कॉल के लक्ष्य के रूप में *foo प्रयोग नहीं करते। उपर्युक्त रूपों के माध्यम से अनुवाद करें - [myArray objectAtIndex: 42] पर कॉल को उपर्युक्त सी फ़ंक्शन कॉल में अनुवादित किया गया है, जिसके बाद समकक्ष सी फ़ंक्शन कॉल घोषणा (सभी विधि सिंटैक्स में तैयार किए गए) के साथ कुछ कॉल करना होगा।

ऑब्जेक्ट संदर्भ के माध्यम से किया जाता है क्योंकि यह मैसेंजर - objc_msgSend() को क्लास तक पहुंच प्रदान करता है ताकि विधि कार्यान्वयन को ढूंढ सके - साथ ही उस संदर्भ के बाद पहला पैरामीटर बन जाए - स्वयं का विधि जिसे अंततः निष्पादित किया जाता है।

यदि आप वास्तव में गहरी, start here जाना चाहते हैं। लेकिन जब तक आपके पास grokked this पूरी तरह से परेशान न हो तब तक परेशान न हों।

+1

ग्रेट उत्तर। धन्यवाद, मैंने एक साल पहले आपके ब्लॉग एंट्री में ठोकर खाई थी, और फिर इसे ग्रोक करने में सक्षम नहीं था, लेकिन ओबीजे-सी के साथ कुछ और समय बाद, मैं खरगोश छेद से गहराई से जाना शुरू कर रहा हूं और अब वास्तव में इसकी सराहना करता हूं। –

10
  1. यह एक सूचक नहीं है, यह किसी ऑब्जेक्ट का संदर्भ है।
  2. यह कोई विधि नहीं है, यह एक संदेश है।
+1

प्रश्न दोहराया गया: आप ऑब्जेक्ट्स के संदर्भों पर विधियों को क्यों कॉल करते हैं, न कि ऑब्जेक्ट स्वयं? :-) – chrisgoyal

+7

@ अज्ञात: आप दूसरे बिंदु से चूक गए। आप एक विधि नहीं बुला रहे हैं, आप एक संदर्भ के माध्यम से एक संदेश भेज रहे हैं। – Chuck

+0

[ऑब्जेक्ट संदेश] वाक्यविन्यास किसी ऑब्जेक्ट को संदेश भेजता है, और ऑब्जेक्ट संदेश के लिए उपयुक्त विधि निष्पादित करता है। – Eonil

2

उद्देश्य-सी रनटाइम को ऑब्जेक्ट को दो अलग-अलग कार्यों में उछालने की आवश्यकता हो सकती है, इसलिए यह ऑब्जेक्ट संदर्भ चाहता है, न कि ऑब्जेक्ट स्वयं।

+0

धन्यवाद। क्या यह तथ्य कहीं भी दस्तावेज है? मैंने जो पुस्तकें पढ़ी हैं उनमें से कोई भी अब तक कवर क्यों नहीं है। – chrisgoyal

+3

स्रोत उपलब्ध है। अगर मेरे पास एक पल है, तो मुझे इस प्रश्न का विस्तार से जवाब देना होगा। यह एक दिलचस्प मुद्दा है और इसमें शामिल सूक्ष्मता है। – bbum

10

क्योंकि objc_msgSend() इस तरह घोषित किया जाता है:

id objc_msgSend(id theReceiver, SEL theSelector, ...) 
4

कारण यह है कि आप नल पॉइंटर अपवाद छोड़ दिया और सही मिलेगा है। nil पर एक संदेश भेजना और अक्सर पूरी तरह से वैध है (यह कुछ भी नहीं करता है और कोई त्रुटि उत्पन्न नहीं करता है)।

लेकिन आप के रूप में अनुरूप सी ++ के -> अंकन इसके बारे में सोच सकते हैं: यह विधि कार्यान्वित और वाक्यात्मक चीनी का एक टुकड़ा में सूचक dereferences।

+0

'nil' को संदेश भेजना उन कारणों में से एक है जिन्हें मैं उद्देश्य-सी पसंद करता हूं। 'If ([myString length])' के साथ एक गैर-रिक्त स्ट्रिंग के लिए परीक्षण करने में सक्षम होना अच्छा है या 'अगर ([myArray count]]' के साथ एक गैर-रिक्त सरणी के लिए परीक्षण करना स्पष्ट रूप से सुनिश्चित करना है कि ऑब्जेक्ट है पूछताछ से पहले मान्य। – dreamlax

6

आप ऑब्जेक्ट पॉइंटर्स, अवधि को कभी भी कम नहीं करते हैं। तथ्य यह है कि उन्हें "वस्तु प्रकार" की बजाय पॉइंटर्स के रूप में टाइप किया गया है, यह भाषा की विरासत का एक आर्टिफैक्ट है। यह जावा के प्रकार सिस्टम के बराबर है, जहां ऑब्जेक्ट्स हमेशा संदर्भों के माध्यम से उपयोग किए जाते हैं। आप जावा में किसी ऑब्जेक्ट को कभी भी खराब नहीं करते - वास्तव में, आप नहीं कर सकते। आपको उनके बारे में पॉइंटर्स के रूप में नहीं सोचना चाहिए, क्योंकि अर्थात्, वे नहीं हैं। वे सिर्फ संदर्भ संदर्भ हैं।

+0

इस तरह के सीधे जवाब के लिए धन्यवाद। – Philip007

4

मैं इस तरह वाक्यांश करता हूं: वर्णमाला की एक श्रृंखला से कौन सी भाषा संबद्ध होती है, यह सिर्फ एक सम्मेलन है। लोग हैं, जो ऑब्जेक्टिव-सी तैयार किया गया फैसला किया है कि

[x doSomething]; 

मतलब "वस्तु एक्स द्वारा बताया करने के लिए doSomething संदेश भेजने"। उन्होंने इसे इस तरह परिभाषित किया, आप नियम का पालन करते हैं :) उदाहरण-की तुलना में उद्देश्य-सी की एक विशिष्टता सी ++, यह है कि इसमें ऑब्जेक्ट को रखने के लिए सिंटैक्स नहीं है, ऑब्जेक्ट करने के लिए पॉइंटर नहीं। तो,

NSString* string; 

ठीक है, लेकिन

NSString string; 

गैर कानूनी है। यदि उत्तरार्द्ध संभव था, तो capitalizedString को एक स्ट्रिंग string पर संदेश capitalizedString को परstring द्वारा इंगित "संदेश" भेजने के लिए एक तरीका होना होगा। लेकिन हकीकत में, आप हमेशा अपने स्रोत कोड में एक चर द्वारा ऑब्जेक्ट पर एक संदेश भेजते हैं।

तो, अगर ऑब्जेक्टिव-सी के डिजाइनर अपने तर्क का पालन किया था, आप

[*x doSomething]; 

हर बार लिखने के लिए आपको एक संदेश भेजने के बाद हमेशा प्रकट करने के लिए होता ... तुम देखो, * जरूरतों अग्रणी ब्रैकेट [, संयोजन [* बना रहा है।उस चरण में, मेरा मानना ​​है कि आप मानते हैं कि भाषा को फिर से डिजाइन करना बेहतर है ताकि आपको के बजाय [ लिखना पड़े, [x doSomething] अक्षरों के अनुक्रम का अर्थ बदलकर।

+0

स्पष्टीकरण के लिए धन्यवाद। तो ऐसा लगता है कि ऑब्जेक्टिव-सी ने उन लोगों की तरह प्रतीत किया है कि आप ऑब्जेक्ट्स को ऑब्जेक्ट पर ऑब्जेक्ट्स पर ऑब्जेक्ट्स को संदेश भेजते हैं। अभी भी उत्सुक * क्यों * उन्होंने इस तरह से चुना ... :-) – chrisgoyal

3

उद्देश्य-सी में एक वस्तु अनिवार्य रूप से struct है। struct का पहला सदस्य Class isa है (struct का कुल आकार isa का उपयोग करके निर्धारित किया जा सकता है)। struct के बाद के सदस्यों में आवृत्ति चर शामिल हो सकते हैं।

जब आप कोई उद्देश्य-सी ऑब्जेक्ट घोषित करते हैं, तो आप हमेशा इसे पॉइंटर प्रकार के रूप में घोषित करते हैं क्योंकि रनटाइम आपके ऑब्जेक्ट को अन्य विधियों और कार्यों को देता है; यदि ये struct (इंस्टेंस चर, आदि को संशोधित करके) के किसी भी सदस्य को बदलते हैं, तो वे “ ” को आपके ऑब्जेक्ट के सभी संदर्भों पर लागू करेंगे, न केवल विधि या फ़ंक्शन के भीतर स्थानीय रूप से।

14

आपको वास्तव में इन्हें पॉइंटर्स-टू-ऑब्जेक्ट्स के रूप में नहीं सोचना चाहिए। यह एक ऐतिहासिक कार्यान्वयन विस्तार की तरह है कि वे पॉइंटर्स हैं, और आप उन्हें सिंटैक्स भेजने वाले संदेश में इसका उपयोग करते हैं (देखें @ bbum का जवाब)। वास्तव में, वे सिर्फ "वस्तु पहचानकर्ता" (या संदर्भ) हैं। चलो वैचारिक तर्क देखने के लिए थोड़ा सा रिवाइंड करें।

उद्देश्य-सी को पहले इस पुस्तक में प्रस्तावित और चर्चा की गई थी: Object-Oriented Programming: An Evolutionary Approach। यह आधुनिक कोको प्रोग्रामर के लिए बेहद व्यावहारिक नहीं है, लेकिन भाषा के लिए प्रेरणा वहां मौजूद है।

ध्यान दें कि पुस्तक में सभी वस्तुओं को id दिया गया है। आपको पुस्तक में अधिक विशिष्ट Object * एस नहीं दिखाई देता है; जब हम "क्यों" के बारे में बात कर रहे हैं तो वे अमूर्तता में केवल एक रिसाव हैं। यहां बताया गया है कि पुस्तक क्या कहती है:

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

ऑब्जेक्ट पहचानकर्ता वास्तव में वस्तु की पहचान कैसे करता है एक कार्यान्वयन विवरण है जिसके लिए कई विकल्प व्यावहारिक हैं। एक उचित विकल्प, निश्चित रूप से सबसे सरल, और उद्देश्य-सी में उपयोग किया जाने वाला एक, वस्तु के भौतिक पते को स्मृति में इसके पहचानकर्ता के रूप में उपयोग करना है। उद्देश्य-सी इस फ़ाइल को प्रत्येक फ़ाइल में टाइप किए गए कथन उत्पन्न करके सी को ज्ञात करता है। यह किसी अन्य प्रकार के संदर्भ में एक नया प्रकार, आईडी परिभाषित करता है जिसे सी पहले से समझता है, अर्थात् संरचनाओं के लिए पॉइंटर्स। [...]

एक आईडी एक निश्चित मात्रा में अंतरिक्ष का उपभोग करती है। [...] यह स्थान ऑब्जेक्ट में निजी डेटा द्वारा कब्जा कर लिया गया स्थान जैसा नहीं है।

(। Pp58-59, 2 एड)

तो आपके सवाल का जवाब दोहरा है:

  1. भाषा डिजाइन निर्दिष्ट करता है कि एक वस्तु का पहचानकर्ता एक के समान नहीं है ऑब्जेक्ट स्वयं, और पहचानकर्ता वह चीज है जिसे आप संदेश भेजते हैं, न कि वस्तु को।
  2. डिज़ाइन निर्देशित नहीं करता है, लेकिन सुझाव देता है कि हमारे पास अब कार्यान्वयन है, जहां ऑब्जेक्ट्स के पॉइंटर्स को पहचानकर्ता के रूप में उपयोग किया जाता है।

सख्ती से टाइप वाक्य रचना तुम कहाँ कहते हैं कि "एक वस्तु विशेष रूप से प्रकार NSString की" और इस प्रकार का उपयोग NSString * एक और अधिक आधुनिक परिवर्तन है, और मूल रूप से एक कार्यान्वयन विकल्प है, id के बराबर है।

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

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

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