2010-11-13 15 views
79

में ivars और गुणों के बीच क्या अंतर है उद्देश्य-सी में 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; 
    } 

उत्तर

56

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

@property घोषित करके, (और .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 

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

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

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

क्या मैंने सब कुछ शामिल किया?

+0

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

+0

त्रुटि क्या है क्या आपको मिलता है? – willc2

+0

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

16

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

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

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

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

+1

यह ध्यान दिया जाना चाहिए कि किसी संपत्ति की परमाणुता [थ्रेड सुरक्षा की गारंटी नहीं देती है] (http://stackoverflow.com/a/589392/603977)। –

+0

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

+2

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