2009-09-19 12 views
23

में शीर्षलेख और कार्यान्वयन फ़ाइलों के साथ भ्रम सबसे पहले, कृपया इस प्रश्न की मूर्खता को क्षमा करें, लेकिन मैं सी/सी ++ पृष्ठभूमि से नहीं हूं। जब मैं संपत्तियों की बात करता हूं तो .h और .m फ़ाइलों के बीच भूमिकाओं में अंतर के बारे में थोड़ा अस्पष्ट हूं।उद्देश्य-सी

मैं इंटरफेस की अवधारणा को समझने, और मुझे लगता है कि भाग में ज फ़ाइल कार्यान्वयन के लिए एक इंटरफेस है, लेकिन मैं क्या पर स्पष्ट नहीं कर रहा हूँ यह है:

  • गुण/तरीकों क्यों परिभाषित कर रहे हैं {} ब्रेसिज़ के बाहर?
  • क्या मैं ब्रेसिज़ में परिभाषित करने जब मैं कुछ इस तरह लिखना हूँ:

    IBOutlet UITextField * numberField;

    क्या यह एक इंटरफ़ेस में फ़ील्ड परिभाषा है?

  • जब मैं .h फ़ाइलों में @Property लाइन जोड़ रहा हूं, तो एन ऑटो प्रॉपर्टी के इन वास्तविक कार्यान्वयन या केवल एक इंटरफ़ेस ब्लूप्रिंट हैं? यदि ऐसा है तो @syntesis वास्तविक कार्यान्वयन है?

मुझे लगता है कि मेरा सबसे बड़ा भ्रम है कि मैं कर रहा हूँ को परिभाषित करता है, तो मैं एक संपत्ति चाहते हैं कि मैं क्या इंटरफेस ब्रेसिज़ में तीन अलग-अलग स्थानों (1) में की जरूरत है, (2) ब्रेसिज़ के बाहर @property के रूप में और हो रहा है (3) .m फ़ाइल में @ सिंथेसिस के साथ। यह लंबे समय तक हवादार लगता है, लेकिन यह ठीक है अगर मैं यह काम कर सकता हूं कि ये तीन हिस्सों क्या करते हैं।

चीयर्स, क्रिस।

उत्तर

75

मैं आपके सवालों का जवाब देंगे नीचे, लेकिन शायद सबसे अच्छा तरीका यह सामान जानने के लिए कुछ उपयोगकर्ता के अनुकूल ऐसे cocoadevcentral पर अधिक the Learn Objective-C tutorial के रूप में भाषा के लिए नए लोगों के लिए करना नोट, पढ़ने के लिए है।

एक उदाहरण

मैं एक उदाहरण (मैं उदाहरण के द्वारा सीखने प्यार) के साथ आपके सवालों के जवाब में मदद करना चाहते हैं। आइए मान लें कि आप एक शिक्षक को एक प्रोग्राम लिख रहे हैं जो छात्रों को एक विशेष हां/कोई सवाल नहीं पूछता है, और यह ट्रैक करता है कि कितने लोग इसे सही करते हैं और कितने छात्रों ने पूछा है।

@interface Question : NSObject { 
    NSString* questionStr; 
    int numTimesAsked; 
    int numCorrectAnswers; 
} 

@property (nonatomic, retain) NSString* questionStr; 
@property (nonatomic, readonly) int numTimesAsked; 
@property (nonatomic) int numCorrectAnswers; 
@property (nonatomic) int numWrongAnswers; 

- addAnswerWithTruthValue: (BOOL) isCorrect; 
@end 

ब्रेसिज़ के अंदर तीन चर उदाहरण चर हैं, और आपके वर्ग के प्रत्येक उदाहरण वे चर से प्रत्येक के लिए अपने स्वयं के मान होगा:

यहाँ इस वर्ग के लिए एक संभव इंटरफेस है। ब्रेसिज़ के बाहर सबकुछ लेकिन @end से पहले एक विधि की घोषणा है (@property घोषणाओं सहित)।

(साइड नोट:। कई वस्तुओं के लिए, यह retain गुण हैं, जब से तुम वस्तु को कॉपी करने की भूमि के ऊपर से बचने के लिए और सुनिश्चित करें कि आप प्रयोग कर रहे हैं, जबकि यह जारी नहीं किया है बनाना चाहते उपयोगी है यह कानूनी है करने के लिए retain इस उदाहरण में एक NSString, लेकिन it is often considered good practice to use copy instead of retain एक NSString* के बाद से वास्तव में एक NSMutableString वस्तु है, जो बाद में बदल सकता है जब आपके कोड यह एक ही रहने की उम्मीद को इंगित कर सकते हैं।)

क्या @property करता

जब आप एक @property का ऐलान करते हैं तो आपको दो बातें कर रहे हैं:

  1. वर्ग के इंटरफ़ेस में एक सेटर और गेटर विधि की घोषणा, और
  2. संकेत कैसे सेटर और गेटर व्यवहार।

    @property (nonatomic, retain) NSString* questionStr; 
    

    मूल रूप से इस रूप में ही है:

    - (NSString*) questionStr;       // getter 
    - (void) setQuestionStr: (NSString) newQuestionStr; // setter 
    
    शीर्षक में

पहले एक के लिए, यह है कि इस लाइन को पता है काफी है। आप सचमुच उन दो तरीकों की घोषणा कर रहे हैं; आप उन्हें सीधे कॉल कर सकते हैं, या डॉट नोटेशन का उपयोग उनको कॉल करने के लिए शॉर्टकट के रूप में कर सकते हैं।

मूल रूप से "मूल रूप से" भाग "मूल रूप से" भाग nonatomic और retain जैसे कीवर्ड द्वारा दी गई अतिरिक्त जानकारी है।

nonatomic कीवर्ड इंगित करता है कि वे आवश्यक रूप से थ्रेड-सुरक्षित नहीं हैं।सामान्य retain कीवर्ड इंगित करता है कि ऑब्जेक्ट सेट किए गए किसी भी मान को बनाए रखता है, और पिछले मानों को रिलीज़ करता है जैसे उन्हें जाने दिया जाता है।

उदाहरण के लिए:

// The correct answer to both questions is objectively YES. 
Question* myQuestion = [[Question alloc] init]; 
NSString* question1 = [[NSString alloc] initWithString:@"Is pizza tasty?"]; 
// question1 has retain count of 1, from the call to alloc 
myQuestion.questionStr = question1; 
// question1 now has a retain count of 2 
NSString* question2 = [[NSString alloc] initWithString:@"Free iPhone?"]; 
myQuestion.questionStr = question2; 
// question1 has a retain count of 1, and question2 has retain count of 2 

तो questionStr के लिए @property घोषणा assign बजाय किया गया था, तो सभी myQuestion.questionStr = बयान किए गए परिवर्तन सभी पर बनाए रखने के लिए मायने रखता है के लिए बनाया नहीं होता।

आप read a little more about properties here कर सकते हैं।

क्या IBOutlet और IBAction

कर ये मूल रूप से कोई-op शब्द जो एक तरह से इंटरफ़ेस बिल्डर जो हेडर फाइल के टुकड़े पर ध्यान देना बताने के लिए के रूप में केवल अभिनय कर रहे हैं। IBOutlet संकलक एक खाली स्ट्रिंग बन जाता है जब संकलक इसे देखता है, और IBActionvoid वापसी मान बन जाता है। हमें इंटरफ़ेस बिल्डर के साथ काम करने की आवश्यकता है, हालांकि, वे महत्वपूर्ण हैं - बस संकलक के लिए नहीं।

सी structs पर त्वरित टिप्पणी और बनाम डॉट नोटेशन

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

struct MyStructType { 
    int i; 
    BOOL b; 
}; 
struct MyStructType* myStruct; 
myStruct->i = 3; 
myStruct->b = TRUE; // or YES in Objective-C. 

यह वही वाक्य रचना ऑब्जेक्टिव-सी में एक ही तरह से काम करता है:

Question* question = [[Question alloc] init]; 
question->questionStr = @"Is this a long answer?"; // YES 

लेकिन जब आप ऐसा करते हैं, तो नहीं डॉट नोटेशन के विपरीत, दृश्यों के पीछे विधि कॉल हो रहा है। डॉट नोटेशन के साथ, आप सेटर कॉल कर रहे हैं (या अगर कोई = है बाद में मनुष्य), और इन दो पंक्तियों में एक ही कर रहे हैं:

question.questionStr = @"Chocolate?"; 
[question setQuestionStr:@"Chocolate?"]; 

यह अक्सर एक अच्छा विचार के पक्ष में तीर अंकन से बचने के लिए है डॉट नोटेशन, चूंकि डॉट नोटेशन आपको वैध स्थिति को लागू करने देता है - उदाहरण के लिए, आपके क्लाइंट को पॉइंटर्स हमेशा बनाए रखा जाता है। आप अपने इंस्टेंस वैरिएबल को @private के रूप में घोषित करके तीर नोटेशन का उपयोग करने से दूसरों को भी अस्वीकार कर सकते हैं; यदि आप इसके लिए @property घोषित करते हैं, तो वे अभी भी गेटटर और सेटर का उपयोग कर सकते हैं।

@synthesize

क्या करता है अब, जब आप चारों ओर करने के लिए वास्तव में अपने वर्ग को लागू करने के लिए, @synthesize का कहना है की तरह कुछ "यकीन है कि मनुष्य और सेटर इस संपत्ति के लिए लागू किया हो सकते हैं।" यह कहता है "इन दोनों को मेरे लिए लागू करें," क्योंकि संकलक पहले आपके स्वयं के कार्यान्वयन की जांच करने के लिए विनम्र है, और केवल आपके द्वारा छोड़े गए टुकड़ों को भरें। आपको @synthesize का उपयोग करने की ज़रूरत नहीं है, भले ही आप @property का उपयोग वज़ू से करें - आप हमेशा अपने सेटर्स और गेटर्स के लिए अपने कार्यान्वयन प्रदान कर सकते हैं, अगर आप उस तरह की चीज में हैं।

आप शायद कि ऊपर Question इंटरफ़ेस में देखा वहाँ एक संपत्ति जो एक उदाहरण चर (numWrongAnswers) है, जो ठीक है क्योंकि आप बस तरीकों घोषणा कर रहे है नहीं है। यहाँ उदाहरण के कोड में, आप देख सकते हैं कि यह कैसे वास्तव में काम करता है:

@implementation Question 

@synthesize questionStr, numTimesAsked, numCorrectAnswers; 

- (void) setNumCorrectAnswers: (int) newCorrectAnswers { 
    // We assume the # increases, and represents new answers. 
    int numNew = newCorrectAnswers - numCorrectAnswers; 
    numTimesAsked += numNew; 
    numCorrectAnswers = newCorrectAnswers; 
} 

- (int) numWrongAnswers { 
    return numTimesAsked - numCorrectAnswers; 
} 

- (void) setNumWrongAnswers: (int) newWrongAnswers { 
    int numNew = newWrongAnswers - self.numWrongAnswers; 
    numTimesAsked += numNew; 
} 

- (void) addAnswerWithTruthValue: (BOOL) isCorrect { 
    if (isCorrect) { 
    self.numCorrectAnswers++; 
    } else { 
    self.numWrongAnswers++; 
    } 
} 

@end 

एक बात है कि यहाँ क्या हो रहा है हम एक उदाहरण चर numWrongAnswers कहा जाता है, जो अनावश्यक जानकारी हो सकता है अगर हम इसे कक्षा में संग्रहीत faking रहे हैं। चूंकि हम जानते हैं कि numWrongAnswers + numCorrectAnswers = numTimesAsked हर समय, हमें केवल इन तीन डेटा बिंदुओं में से किसी एक को स्टोर करने की आवश्यकता है, और हम हमेशा उन दो मूल्यों का उपयोग करके दूसरे के संदर्भ में सोच सकते हैं जिन्हें हम जानते हैं। यहां बिंदु यह समझना है कि @property घोषणा वास्तव में केवल एक सेटटर और गेटर विधि घोषित करने के बारे में है, जो आम तौर पर एक वास्तविक आवृत्ति चर के अनुरूप होती है - लेकिन हमेशा नहीं। @synthesize डिफ़ॉल्ट रूप से कीवर्ड एक वास्तविक आवृत्ति चर के अनुरूप है, ताकि संकलक के लिए आपके लिए कार्यान्वयन भरना आसान हो।

कारण अलग .h और .m फ़ाइलों

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

मुझे उम्मीद है कि यह सहायक है!

+1

का उपयोग करके केवल गुणों का उपयोग किया जाता है, एक समग्र प्रभावशाली पोस्ट की कुछ रचनात्मक आलोचना: (1) एनएसएसटींग गुणों को वास्तव में बनाए रखने के रूप में चिह्नित किया जाना चाहिए, (2) मुझे लगता है कि आप क्यों चाहते हैं .m और .h फ़ाइलों की आवश्यकता नहीं है इस संदर्भ में क्या चल रहा है इसके साथ रहना बेहतर है। मुझे पसंद आया कि आपने आईबीओलेट और आईबीएक्शन के उद्देश्य के बारे में बात की थी। –

+3

असल में, एनएसएसटींग गुणों को कॉपी के रूप में चिह्नित किया जाना चाहिए। – bbum

+0

ओह, मेरा यही मतलब था - उदाहरण कोड पहले से ही इसे बनाए रखने के रूप में है ...मेरी गलती को सुधारने के लिए धन्यवाद! –

1
  1. तरीकों ब्रेसिज़ के बाहर परिभाषित कर रहे हैं के बाद से ब्रेसिज़ वस्तु जो तर्क दिया जा सकता उदाहरण या वर्ग के तरीकों को शामिल नहीं करता की स्थिति को संपुटित लिए होती हैं।

  2. क्या आप ब्रेसिज़ में परिभाषित कर रहे हैं उदाहरण चर के लिए आप उदाहरण चर self.ivar के रूप में संदर्भित किया जा सकता

  3. @property और @synthesize निर्देशों बस सेटअप accessors ताकि आप उन्हें स्वयं करके सेट कर सकते हैं कर रहे हैं .ivar = someVar। तो दूसरे शब्दों में यह आपके उपयोग के लिए "डॉट सिंटैक्स" सेट करता है।

और अपने समापन समारोह सवाल का जवाब देने: एक संपत्ति या उदाहरण चर को परिभाषित करने के लिए बस ब्रेसिज़ के अंदर एक चर के रूप में अपने ज फाइल में यह घोषणा करते हैं। उसी संपत्ति पर एक्सेसर विधियों को सेट करने के लिए आपको दोनों @property और @ सिंथेसाइज़ करने की आवश्यकता है।

+0

वास्तव में, उदाहरण चर को स्वयं-> ivar के रूप में उपयोग किया जाता है। self.ivar – newacct

0
  1. वैसे यह केवल उद्देश्य सी वाक्यविन्यास, विधियों और @ प्रॉपर्टी के बाहर {} और चर {} के अंदर है।

  2. @property यह कहने का तरीका है कि आप गेटर और सेटर्स (इसे लागू करने के प्रकार) लिखने जा रहे हैं, लेकिन आप उन्हें @property सेट किए बिना गेटर/सेटर लिख सकते हैं। @property .h फ़ाइल में है क्योंकि इसकी घोषणा है। और यह बाहर क्यों है {}, जैसा कि मैंने सिंटैक्स से पहले कहा था, हम क्या कर सकते हैं?

  3. @ सिंथेसिस वास्तविक रूप से गेटटर और सेटर्स को कार्यान्वित करेगा, यदि आप संश्लेषण नहीं करते हैं लेकिन आपने उन्हें @property सेट किया है, तो आपको अपने हाथ से उन गेटटर और सेटर्स को लागू करना होगा। और @ सिंथेसिस .m फ़ाइल में है क्योंकि इसका कार्यान्वयन।

इस विषय पर पढ़ने के लिए आपके लिए कुछ और भी मिल सकता है।

http://theocacao.com/document.page/510

0

ब्रैकेट के अंदर चर भौतिक संरचना को अपनी कक्षा के परिभाषित करते हैं। वे वास्तविक आवृत्ति चर हैं जो जानकारी संग्रहीत करते हैं।

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

कार्यान्वयन फ़ाइल के अंदर, आप वर्ग को बताते हैं कि वास्तव में अपना काम कैसे करें। विधियों के लिए, जाहिर है, आप केवल एक कार्यान्वयन की आपूर्ति करते हैं। किसी संपत्ति के लिए, आप या तो एक्सेसर कार्यान्वयन स्वयं प्रदान कर सकते हैं या इसे आवृत्ति चर के लिए एक्सेसर्स को संश्लेषित करने के लिए कह सकते हैं।

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

  • कोई संबंधित समस्या नहीं^_^