उद्देश्य-सी में ivars और गुणों के बीच अंतर क्या है


82

उद्देश्य-सी में ivars और गुणों का उपयोग करने के इन 3 तरीकों के बीच क्या अर्थ है?

1।

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;

2।

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;

3।

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}

जवाबों:


57

नंबर 1 कंपाइलर और लिंकर द्वारा देखे गए कोड की मात्रा को कम करने के लिए MyOtherObject वर्ग की घोषणा करके अन्य दो से भिन्न होता है और संभावित रूप से परिपत्र संदर्भों से भी बचता है। अगर आप इसे इस तरह करते हैं तो # मीम को .m फ़ाइल में रखना याद रखें।

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

इसके अलावा, एक संश्लेषित संपत्ति की घोषणा करने से आप इस तरह डॉट नोटेशन का उपयोग कर एक एक्सेसर विधि को कॉल कर सकते हैं:

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 

सामान्य के बजाय, संदेश-गुजरने का तरीका:

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 

पर्दे के पीछे आप वास्तव में इस तरह दिखने वाली एक विधि कह रहे हैं:

- (void) setOtherObj:(MyOtherObject *)anOtherObject {

    if (otherObject == anOtherObject) {
        return;  
    }

    MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
    otherObject = [anOtherObject retain]; // put the new value in  
    [oldOtherObject release]; // let go of the old object
} // set it

…या यह

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it

बट में कुल दर्द, सही। अब कक्षा में प्रत्येक आइवर के लिए ऐसा करें । यदि आप इसे बिल्कुल ठीक नहीं करते हैं, तो आपको एक स्मृति रिसाव मिलता है। कम्पाइलर को काम करने देने के लिए सबसे अच्छा है।

मैं देखता हूं कि नंबर 1 में एक आइवर नहीं है। यह मानते हुए कि एक टाइपो नहीं है, यह ठीक है क्योंकि @property / @synthesize निर्देश आपके लिए एक ivar घोषित करेगा, साथ ही पर्दे के पीछे भी। मेरा मानना ​​है कि मैक ओएस एक्स - स्नो लेपर्ड और आईओएस 4 के लिए यह नया है।

नंबर 3 में वे एक्सेसर्स उत्पन्न नहीं होते हैं, इसलिए आपको उन्हें स्वयं लिखना होगा। यदि आप चाहते हैं कि आपके एक्सेसर के तरीकों के साइड इफेक्ट्स हों, तो आप अपना स्टैण्डर्ड मेमोरी मैनेजमेंट डांस करते हैं, जैसा कि ऊपर दिखाया गया है, तो एक्सेसर मेथड के अंदर आपको जो भी साइड वर्क करना है, वह करें। यदि आप एक संपत्ति को संश्लेषित करते हैं और साथ ही अपना खुद का लिखते हैं , तो आपके संस्करण की प्राथमिकता है।

क्या मैंने सब कुछ कवर किया?


हाँ आप का बहुत धन्यवाद! एक नोट जो मैं करना चाहता हूं वह यह है कि यदि आप # 1 में फॉरवर्ड क्लास के प्रैग्मा को निकालते हैं और इसे #import "MyOtherObject" से बदल देते हैं, तो आपको एक संकलन समय त्रुटि मिलती है, निश्चित रूप से हालांकि क्यों नहीं ...
ennuikiller

क्या दृष्टिकोण # 2 ओवर # 1 का उपयोग करने का कोई फायदा है?
ग्रेग

@Greg विधि # 1 एक परिपत्र संदर्भ को रोक देगा। देखें stackoverflow.com/questions/7221174/...
willc2

3
डॉट नोटेशन के बारे में बिट को छोड़कर अच्छा जवाब। आपको इसे डॉट नोटेशन के लिए उपयोग करने के लिए संपत्ति को संश्लेषित करने की आवश्यकता नहीं है। वास्तव में, आपको एक संपत्ति घोषित करने की आवश्यकता नहीं है। जब तक आपके पास एक घोषित सेटर और गेट्टर (जैसे ) हैं setFoo:और fooआप डॉट नोटेशन का उपयोग कर सकते हैं।
जेरेमीप

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

17

पुराने दिनों में आपके पास हाथीदांत था, और यदि आप किसी अन्य वर्ग को सेट करने देना चाहते थे या उन्हें पढ़ना चाहते थे, तो आपको एक गेटर (यानी, -(NSString *)foo)और एक सेटर (यानी, -(void)setFoo:(NSString *)aFoo;) को परिभाषित करना होगा ।

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

ये क्या @synthesizeकरता है बहुत से लोग ivar नाम को छोड़ देते हैं, लेकिन आप इसे बदल सकते हैं जब आप अपना सिंथेसाइज़ स्टेटमेंट लिखते हैं (यानी, संपत्ति के लिए @synthesize foo=_foo;ivar नाम बनाते _fooहैं foo, इसलिए यदि आप इस संपत्ति को पढ़ना या लिखना चाहते हैं और आप उपयोग नहीं करते हैं self.foo, तो आप कर सकते हैं _foo = ...अगर आपको केवल सेटर और गेट्टर के माध्यम से जाना है तो इसका उपयोग करने में मदद करता है - यदि आप केवल आइवर के लिए सीधे संदर्भ को पकड़ना चाहते हैं)।

Xcode 4.6 के रूप में, आपको @synthesizeकथन का उपयोग करने की आवश्यकता नहीं है - संकलक इसे स्वचालित रूप से करेगा और डिफ़ॉल्ट रूप से ivar के नाम के साथ प्रीपेन्ड करेगा _


1
यह ध्यान दिया जाना चाहिए कि किसी संपत्ति की परमाणुता थ्रेड सुरक्षा की गारंटी नहीं देती है
jscs

इसलिए अगर मेरे पास एक आइवर है जो परमाणु है, तो आप का मतलब है कि जब सेटर इसे सेट कर रहा है या गेट्टर मिल रहा है, तो एक और धागा अंदर घुसता है और या तो करने की कोशिश करता है, कि यह सब गड़बड़ हो जाता है? फिर परमाणु का क्या मतलब है? मेरी समझ यह है कि परमाणु कम से कम यह सुनिश्चित करता है कि यदि आप एक आइवर सेट करते हैं, तो यह सेट हो जाता है, इसकी रिटेन गिनती उचित है आदि अन्यथा परमाणु क्यों? [ऐसा नहीं है कि यह सभी समस्याओं को हल करता है बस आपको भयभीत होने से रोकता है]
डेविड एच

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

ठीक है, मैं तर्क दूंगा कि आपकी मूल टिप्पणी गलत बताई गई है - परमाणुता का सम्मान किया जाता है, बस इसके थ्रेड्स के माध्यम से एक्सेस करने से समस्याओं का एक बहुत कुछ हो सकता है - इस प्रकार, मैंने कभी भी घोषित किया हर हाथी परमाणु है और अगर थ्रेड्स हैं तो संगामिति कहीं और से निपटा जाता है।
डेविड एच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.