2012-01-12 6 views
20

@implementation के बजाय @interface में एक निजी ivar घोषित करने का कोई कारण है?@interface में निजी ivar या @ कार्यान्वयन

मैं सभी (Apple से प्राप्त दस्तावेज़ों सहित) इंटरनेट पर इस तरह कोड देखें:

Foo.h

@interface Foo : NSObject { 
@private 
    id _foo; 
} 
@end 

Foo.m

@implementation Foo 
// do something with _foo 
@end 

हेडर फ़ाइल कक्षा के सार्वजनिक इंटरफ़ेस को परिभाषित करती है, जबकि एक निजी इवर है ... अच्छा ... निजी। तो इसे इस तरह घोषित क्यों न करें?

Foo.h

@interface Foo : NSObject 
@end 

Foo.m @implementation में

@implementation Foo { 
@private 
    id _foo; 
} 

// do something with _foo 
@end 

उत्तर

24

घोषणा उदाहरण चर Obj सी के हाल के एक सुविधा है, यही कारण है कि आप एक बहुत देखते हैं @interface में उनके साथ कोड का - कोई अन्य विकल्प नहीं था।

यदि आप एक कंपाइलर का उपयोग कर रहे हैं जो कार्यान्वयन में आवृत्ति चर घोषित करने का समर्थन करता है तो उन्हें घोषित करना संभवतः सबसे अच्छा डिफ़ॉल्ट है - केवल उन्हें इंटरफेस में डाल दें यदि उन्हें दूसरों द्वारा एक्सेस किया जाना चाहिए।

संपादित करें: अतिरिक्त जानकारी

उदाहरण चर कार्यान्वयन में घोषित कर रहे हैं परोक्ष छिपा (प्रभावी रूप से निजी) और दृश्यता बदला नहीं जा - @public, @protected और @private संकलक त्रुटियों का उत्पादन नहीं करते (साथ कम से कम वर्तमान क्लैंग) लेकिन अनदेखा कर रहे हैं।

+1

विशेष रूप से, प्रश्न में संकलक क्लैंग> 2. (मौजूदा) जीसीसी ऐसा नहीं करेगा। –

+0

इस संदर्भ में, 'क्लैंग' 'एलएलवीएम' जैसा ही है, है ना? –

+0

@ranReloaded - नहीं। जीसीसी-जीसीसी फ्रंट एंड बैकएंड, जीसीसी-एलएलवीएम - जीसीसी फ्रंटएंड, एलएलवीएम बैकएंड - और क्लैंग - क्लैंग फ्रंटएंड, एलएलवीएम बैकएंड है। मैंने केवल क्लैंग पर परीक्षण किया, जोश ने जीसीसी के एक परीक्षण पर परीक्षण किया। वाईएमएमवी, बस आप जिस भी कंपाइलर का उपयोग कर रहे हैं उसे देखें और देखें। – CRD

4

यदि आपको पुराने सिस्टम या एक्सकोड के रिलीज को संकलित करने के लिए संकलक समर्थन की आवश्यकता है तो आप @interface का पक्ष लेंगे।

यदि आप निश्चित हैं कि आपको पिछली संगतता की आवश्यकता नहीं होगी, तो मैं कहूंगा कि इसे @implementation में रखना सर्वोत्तम है।

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

निर्देशों @public, @protected, और @private उद्देश्य-सी में बाध्यकारी नहीं हैं, वे संकलक के बारे में चर की पहुंच संकेत कर रहे हैं। यह आपको उन तक पहुंचने से प्रतिबंधित नहीं करता है।

उदाहरण:

@interface Example : Object 
{ 
@public 
int x; 
@private 
int y; 
} 
... 


... 
id ex = [[Example alloc ] init]; 
ex->x = 10; 
ex->y = -10; 
printf(" x = %d , y = %d \n", ex->x , ex->y); 
... 

जीसीसी संकलक बाहर थूक:

main.m: 56: 1: चेतावनी: उदाहरण चर 'y' @private है; भविष्य में यह एक कठिन त्रुटि होगी

मुख्य.एम: 57: 1: चेतावनी: आवृत्ति चर 'y' @private है; इस बार "निजी" सदस्य y करने के लिए प्रत्येक "innapropriate" एक्सेस का भविष्य

में एक कठिन त्रुटि हो, लेकिन यह वैसे भी संकलित करेंगे।

जब चलाने आप

x = 10 , y = -10 

तो यह वास्तव में एक्सेस कोड इस तरह से लिखने के लिए नहीं आप पर निर्भर है, लेकिन क्योंकि ObjC एक सुपरसेट सी के है, सी वाक्य रचना बस ठीक काम करता है, और सभी मिल कक्षाएं पारदर्शी हैं।

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

उद्देश्य-सी में सदस्यों की गोपनीयता प्राप्त करने के लिए कई चालें हैं। एक यह सुनिश्चित करना है कि आप अपनी कक्षा के इंटरफ़ेस और कार्यान्वयन को क्रमशः अलग .h और .m फ़ाइलों में रखें, और डेटा सदस्यों को कार्यान्वयन फ़ाइल (.m फ़ाइल) में रखें। फिर हेडर आयात करने वाली फ़ाइलों के पास डेटा सदस्यों तक पहुंच नहीं है, केवल कक्षा ही। फिर शीर्षलेख में पहुंच विधियां (या) प्रदान करें। यदि आप चाहते हैं तो डायग्नोस्टिक उद्देश्यों के लिए कार्यान्वयन फ़ाइल में आपटर/गेटर फ़ंक्शंस लागू कर सकते हैं और वे कॉल करने योग्य, होंगे लेकिन डेटा सदस्यों तक सीधी पहुंच नहीं होगी।

उदाहरण:

@implementation Example2 :Object 
{ 
//nothing here 
} 
double hidden_d; // hey now this isn't seen by other files. 
id classdata; // neither is this. 

-(id) classdata { return [classdata data]; } // public accessor 
-(void) method2 { ... } 
@end 

// this is an "informal category" with no @interface section 
// these methods are not "published" in the header but are valid for the class 

@implementation Example2 (private) 
-(void)set_hidden_d:(double)d { hidden_d = d; } 

// You can only return by reference, not value, and the runtime sees (id) outside this file. 
// You must cast to (double*) and de-reference it to use it outside of this file. 
-(id) hidden_d_ptr { return &hidden_d;} 
@end 

... 
[Main.m] 
... 
ex2 = [[Example2 alloc] init]; 

double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’ 
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’ 
id data = [ex2 classdata] // OK 

[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:' 

double* dp = [ex2 hidden_d_ptr]; // (SO UGLY) warning: initialization from incompatible pointer type 
           // use (double*)cast -- <pointer-to-pointer conversion> 
double d = (*dp); // dereference pointer (also UGLY). 

... 

संकलक ऐसे ज़बरदस्त धोखाधड़ी के लिए चेतावनी जारी करेगा, लेकिन आगे जाना होगा और विश्वास आप जानते हैं कि आप क्या कर रहे हैं, और कि आप अपने कारणों (करते हैं (वास्तव में?) आप?)। बहुत सारे काम की तरह लगता है? प्रवण त्रुटि? हाँ बेबी! इस तरह जादू सी चाल और मीटबॉल सर्जरी का सहारा लेने से पहले अपने कोड को दोबारा करने का प्रयास करें।

लेकिन वहां है। सौभाग्य।

+0

मैं आईओएस पर 'डबल' से दूर रहूंगा;) –

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