कोको उद्देश्य-सी वर्ग के काम में एक चर के सामने एक अंडरस्कोर कैसे होता है?


157

मैंने कुछ iPhone उदाहरणों में देखा है कि विशेषताओं ने चर के सामने एक अंडरस्कोर _ का उपयोग किया है। क्या किसी को पता है कि इसका क्या मतलब है? या यह कैसे काम करता है?

एक इंटरफ़ेस फ़ाइल जो मैं उपयोग कर रहा हूँ, वह इस प्रकार है:

@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

मुझे यकीन नहीं है कि उपरोक्त क्या करता है, लेकिन जब मैं मिशन नाम सेट करने की कोशिश करता हूं जैसे:

aMission.missionName = missionName;

मुझे त्रुटि मिली:

सदस्य 'मिशननाम' के लिए अनुरोध एक संरचना या संघ में नहीं

जवाबों:


97

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

@synthesize missionName = _missionName;

अधिक उदारता से, यह है:

@synthesize propertyName = _ivarName;

78
ऑटो-सिंथेसाइजिंग गुणों के साथ यह अब आवश्यक नहीं है। Xcode परदे के पीछे _xxxx नामक एक ivar के साथ @property xxxx को संश्लेषित करता है। साफ।
LearnCocos2D

@ LearnCocos2D हाय! IOS के लिए एक नौसिखिया यहाँ और वहाँ कुछ मैं स्पष्ट करने की जरूरत है। इस समय के लिए मैंने जो कुछ भी किया है property, वह .h फ़ाइल में घोषित किया गया था और .mie fie में मैं इसका उपयोग कर रहा हूँ self, जैसे self.someProperty। क्या यह सही तरीका है? या मुझे कोड में ivars का उपयोग करना चाहिए?
इसुरु

ivar सेट करना प्रॉपर्टी सेटर को नहीं चलाता है - आप तय करते हैं कि यह अच्छा विचार है या प्रत्येक विशेष मामले के लिए नहीं
LearnCocos2D

Noob सवाल: क्यों ivars सीधे उपयोग नहीं? मुझे आइवर धारण करने के लिए एक अलग संस्करण क्यों घोषित करना चाहिए?
एलन

1
@ सभी, यदि मैं आपके प्रश्न को सही ढंग से समझता हूं: आप जिस भिन्न संस्करण की घोषणा कर रहे हैं, वह वास्तविक चर का सूचक है। यह कुछ कारणों (जो मुझे पता है) के लिए महत्वपूर्ण है सबसे पहले, जब आप एक फ़ंक्शन में एक पॉइंटर पास करते हैं तो आप इसका मूल्य डुप्लिकेट नहीं कर रहे हैं। आप केवल उस फ़ंक्शन को बता रहे हैं जहां उपयोग करने के लिए मूल्य ढूंढना है। यह आपकी उपयोग की गई मेमोरी को कम रखने में मदद करता है (और मेमोरी के आवंटन और डीलकोल के साथ भी मदद करता है, जो 'कचरा संग्रह' की अनुपस्थिति में महत्वपूर्ण है जो आपको जावा में मिलेगा)
डेविड सिगले

18

यह सिर्फ पठनीयता के लिए एक सम्मेलन है, यह संकलक के लिए कुछ खास नहीं करता है। आप देखेंगे कि लोग इसे निजी उदाहरण चर और विधि नामों पर उपयोग करते हैं। Apple वास्तव में अंडरस्कोर का उपयोग नहीं करने की सलाह देता है (यदि आप सावधान नहीं हो रहे हैं तो आप अपने सुपरक्लास में कुछ ओवरराइड कर सकते हैं), लेकिन आपको उस सलाह को अनदेखा करने के बारे में बुरा नहीं मानना ​​चाहिए। :)


19
मैं जो समझता हूं, Apple विधि नामों पर अंडरस्कोर उपसर्ग का उपयोग करने के खिलाफ सिफारिश करता है (वे निजी तरीकों के लिए एक सम्मेलन के रूप में खुद के लिए आरक्षित करते हैं), लेकिन उदाहरण के चर नामों के बारे में उनके पास ऐसी कोई सिफारिश नहीं है।
केलन

9
@ केलन वास्तव में, Apple ऐसा करने के लिए प्रोत्साहित करता है : "आम तौर पर, आपको सीधे इंस्टेंस चर का उपयोग नहीं करना चाहिए, इसके बजाय आपको एक्सेसर विधियों का उपयोग करना चाहिए (आप सीधे इनवे और डीललॉक विधियों में एक्सेस वेरिएबल्स का उपयोग करते हैं)। इसे संकेत देने में मदद करने के लिए, उपसर्ग उदाहरण। एक अंडरस्कोर (_) के साथ चर नाम, उदाहरण के लिए: \ @ कार्यान्वयन MyClass {BOOL _shTTitle;} "
dmirkitanov

मुझे वास्तव में नहीं लगता कि Apple हमें ऐसा करने के लिए प्रोत्साहित करता है, क्योंकि iOS डेवलपर लाइब्रेरी न में उनके सभी सैंपल कोड उनमें ( ) हैं। Apple यह भी कहता है कि उन्होंने इसे आरक्षित कर दिया है, जिसका अर्थ यह होना चाहिए कि वे इसका उपयोग आंतरिक रूप से UIKit आदि जैसे फ्रेमवर्क के लिए करते हैं। यही कारण है कि हमें लापरवाही से इसका उपयोग नहीं करना चाहिए। लेकिन मुझे लगता है कि, लिंक में आपने @kelan प्रदान किया है। वे वास्तव में "संशोधन इतिहास" में कहते हैं कि यह उपयोग करने के लिए "उपयुक्त" है ( )। मैं व्याख्या करता हूं कि जैसा हम चाहते हैं, हम उसका "उपयोग" कर सकते हैं।
डब्ल्यूएस

एप्पल के दस्तावेज जो कहते हैं कि विधि नामों के लिए अंडरस्कोर उपसर्ग का उपयोग नहीं करना है
थॉमस डब्ल्यूडब्ल्यू

9

मेरे द्वारा देखा गया एकमात्र उपयोगी उद्देश्य स्थानीय चर और सदस्य चर के बीच अंतर करना है, जैसा कि ऊपर कहा गया है, लेकिन यह एक आवश्यक सम्मेलन नहीं है। जब एक @property के साथ जोड़ा जाता है, तो यह संश्लेषित बयानों की क्रिया-क्षमता को बढ़ाता है - @synthesize missionName = _missionName;और हर जगह बदसूरत होता है।

अंडरस्कोर का उपयोग करने के बजाय, केवल उन तरीकों के भीतर वर्णनात्मक चर नामों का उपयोग करें जो संघर्ष नहीं करते हैं। जब उन्हें संघर्ष करना चाहिए, तो विधि के भीतर चर नाम को अंडरस्कोर भुगतना चाहिए, न कि सदस्य चर जिसे कई विधियों द्वारा उपयोग किया जा सकता है । एकमात्र सामान्य स्थान यह उपयोगी है एक सेटर में या एक init विधि में। इसके अलावा, यह @synthesize स्टेटमेंट को और अधिक संक्षिप्त बना देगा।

-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

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


यह दूसरा रास्ता है। निजी चर अंडरस्कोर है। संपत्ति नहीं। और उन्हें आप उन्हें युगल संश्लेषित कर रहे हैं।
जस्टिन

यह ठीक उसी तरह है जैसा मैं वर्णन करता हूं, सिवाय इसके कि मैंने इसे "निजी चर" के बजाय "सदस्य चर" कहा।
पीटर देवेसे

आउच! यह परेशानी पूछ रहा है ... ऑटो-सिंथेसिस ivar _myString का अर्थ देगा कि आपका सेटर काम नहीं करेगा (क्योंकि तब यह आपके आइवर को विधि पैरामीटर से नहीं बता पाएगा)।
जियोवर

सही है, यही वजह है कि मैंने सेब को ऑटो-सिंथेसिस से जोड़ा तो अंत में एडिट किया।
पीटर डेविस

5

इसका वास्तव में कोई मतलब नहीं है, यह सिर्फ एक सम्मेलन है जिसे कुछ लोग स्थानीय चर से सदस्य चर को अलग करने के लिए उपयोग करते हैं।

त्रुटि के लिए, ऐसा लगता है कि विखंडन में गलत प्रकार है। इसकी घोषणा क्या है?


यह IDE के अंतर्कलह के साथ आम है; यह आपके सदस्य / मॉड्यूल / वर्ग चर को सूची में सबसे ऊपर दिखाएगा। एक अन्य आम प्रिविक्स "m_" है
STW

1
अगर इसका कोई मतलब नहीं है तो आप मेरे उदाहरण में _missionName और MissionName के बीच आगे और पीछे कैसे स्विच कर सकते हैं? मेरी घोषणा इस प्रकार है: मिशन * aMission = [[मिशन आवंटन] init]; aMission.missionName = @ "एक मिशन";
आत्मा

1
एक उदाहरण चर है और दूसरा गुण है। आप इंस्टेंस के साथ इंस्टेंस वैरिएबल का उपयोग नहीं कर सकते जैसे aission.missionName, क्योंकि सिंटैक्स पॉइंटर्स के साथ काम नहीं करता है।
चक

इसके अलावा, ध्यान दें कि आप किसी मिशन ऑब्जेक्ट पर काम करने की कोशिश कर रहे हैं, लेकिन आपने जो मिशननामे प्रॉपर्टी के साथ पोस्ट किया है, वह एक मिशनसेल है।
सूंघ

2

यह केवल संश्लेषित गुणों के नामकरण सम्मेलन के लिए है।

जब आप .m फ़ाइल में वेरिएबल्स को संश्लेषित करते हैं, तो Xcode स्वचालित रूप से आपको _variable बुद्धिमत्ता प्रदान करेगा।


1

अंडरस्कोर होने से न केवल सेल्फमबर्ग सिंटैक्स का उपयोग किए बिना अपने आइवर को हल करना संभव हो जाता है, बल्कि यह आपके कोड को और अधिक पठनीय बनाता है, क्योंकि आप जानते हैं कि जब एक वेरिएबल ivar होता है (इसके अंडरस्कोर उपसर्ग के कारण) या सदस्य तर्क (कोई अंडरस्कोर नहीं) )।

उदाहरण:

- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}

इस उदाहरण में self.image (या [self image]) के उपयोग की तुलना करना अच्छा होगा। स्व.इमेज का उपयोग करना कब बेहतर है और _image का उपयोग करना कब बेहतर है?
बोकेम

2
@ बोकेम: आम तौर पर, आपको self.imageसंपत्ति का उपयोग करना चाहिए । एक ही समय में आपको उदाहरण चर का उपयोग करना चाहिए _image, सीधे initतरीकों और deallocविधि के भीतर , जब किसी अन्य विधि को कॉल करना जोखिम भरा हो सकता है (चूंकि वस्तु आधा-आरंभीकृत या आधा-निपटारा है)।
पीटर होसी

1

ऐसा लगता है कि self.variableName बनाम _variablename के बारे में प्रश्नों के लिए "मास्टर" आइटम है। मुझे एक पाश के लिए फेंक दिया गया था जो कि .h में था, मेरे पास था:

...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

इससे self.variableName और _variableName दो अलग-अलग चर होते हैं। मुझे क्या चाहिए था:

...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

फिर, वर्ग में '.m, self.variableName और _variableName बराबर हैं।

मैं अभी भी स्पष्ट नहीं हूं कि कई उदाहरण अभी भी क्यों काम कर रहे हैं, यहां तक ​​कि यह भी कठिन नहीं है।

रे


0

अंडरस्कोर के बजाय आप स्व। नाम का उपयोग कर सकते हैं या आप अंडरस्कोर के बिना वेरिएबल या आउटलेट का उपयोग करने के लिए चर का संश्लेषण कर सकते हैं।


2
अगर आपको केवल उसी वर्ग में चर की आवश्यकता है, तो उसे केवल .m फ़ाइल में ही घोषित करें, तो यह आपको स्वयं या बिना अंडरस्कोर के कॉल करने की अनुमति देगा
अंसल एंटनी

0

अन्य उत्तरों _variableसे चूक यह है कि उपयोग करने से आप अनुपस्थित टाइपिंग variable(ivumlyly) के बजाय संपत्ति पर पहुँचने और अनुपस्थित होने से रोकता है।

संकलक आपको self.variableया तो उपयोग करने के लिए मजबूर करेगा _variable। अंडरस्कोर का उपयोग करना टाइप करना असंभव बनाता है variable, जो प्रोग्रामर त्रुटियों को कम करता है।

- (void)fooMethod {

    // ERROR - "Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

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