2011-11-20 11 views
23

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

ए। विभिन्न पदों के अनुसार और यहां तक ​​कि एक नए स्टैनफोर्ड विश्वविद्यालय आईफोन विकास पाठ्यक्रमों के अनुसार, आपको हमेशा हर जगह संपत्तियों का उपयोग करना चाहिए। हालांकि आईएमएचओ, यह दृष्टिकोण ओओपी डिजाइन सिद्धांतों को तोड़ देता है क्योंकि इस मामले में, सभी सदस्य सार्वजनिक हो जाते हैं। मुझे अपने सभी आंतरिक/स्थानीय आवृत्ति चर को बाहर से प्रकाशित करने की आवश्यकता क्यों है? इसके अलावा, कुछ छोटे (लेकिन अभी भी) ओवरहेड हैं यदि आप गुणों के माध्यम से संश्लेषित सेटर्स का उपयोग करते हैं, बजाय स्थानीय इवर का उपयोग सीधे करते हैं। के लिए

//==== header file =====// 
@interface MyClass : NSObject 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 
@property (nonatomic, retain) NSString *propertyForPrivateMember; 

@end 

बी एक और दृष्टिकोण निजी सदस्यों के लिए (सापेक्ष गुण की घोषणा के बिना) हेडर फाइल में ivars घोषित करने के लिए है, और एक ही हेडर फाइल में, शुद्ध गुण (सापेक्ष ivars की घोषणा के बिना) घोषित करने के लिए: यहाँ एक नमूना है सार्वजनिक सदस्य ऐसे मामले में, ivars सीधे कक्षा में इस्तेमाल किया जाएगा। यह दृष्टिकोण समझ में आता है लेकिन गुणों से सभी लाभों का उपयोग नहीं करता है क्योंकि हमने नए सेट करने से पहले मैन्युअल रूप से पुराने मान जारी किए हैं।

//==== header file =====// 
@interface MyClass : NSObject{ 
    NSString *_privateMember; 
} 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 

@end 

सी हेडर फाइल में सार्वजनिक सदस्यों के लिए (सापेक्ष ivars की घोषणा के बिना) शुद्ध गुण की घोषणा करने के लिए, और कार्यान्वयन फ़ाइल में निजी इंटरफेस में निजी सदस्यों के लिए (सापेक्ष ivars की घोषणा के बिना) शुद्ध गुण घोषित करने के लिए: यहाँ एक नमूना है । यह दृष्टिकोण आईएमएचओ पहले की तुलना में अधिक स्पष्ट है, लेकिन वही सवाल बनी हुई है: हमें आंतरिक/स्थानीय सदस्यों के लिए संपत्ति क्यों है? यहां एक नमूना है:

//==== header file =====// 
@interface MyClass : NSObject 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 

@end 

//==== implementation file =====// 
@interface MyClass() 

@property (nonatomic, retain) NSString *propertyForPrivateMember; 

@end 

इस निर्णय से स्वतंत्रता मुझे एक छोटा सा गुस्सा दिलाती है और मैं कैसे चीजें किया जाना चाहिए के बारे में संबंधित स्रोतों से एक पुष्टिकरण प्राप्त करना चाहते हैं। हालांकि, मैं उस पर ऐप्पल दस्तावेज़ों में ऐसे सख्त वक्तव्य नहीं ढूंढ पा रहा था, इसलिए यदि कोई मौजूद है, तो किसी भी मौजूद सिद्धांत से, या किसी अन्य सिद्धांत के लिए एक लिंक पोस्ट करें।

+0

यह प्रश्न सही तरीके से उत्तर देने के लिए बहुत ही व्यक्तिपरक और असंभव प्रतीत होता है। – Till

+0

प्रश्न बहुत सरल है - निजी और सार्वजनिक सदस्यों को उद्देश्य-सी में कैसे लागू किया जाना चाहिए, और जहां मैं उस पर ऐप्पल सख्त आवाज पा सकता हूं। – Centurion

+1

मैं अलग होना चाहता हूं लेकिन चर्चा में गहराई से नहीं जाऊंगा। मेरे दावे को साबित करने के संकेत के रूप में, आपने स्वयं को नोट किया कि उदा। स्टैनफोर्ड पाठ्यक्रम हर जगह गुणों का उपयोग करने की सलाह देते हैं। – Till

उत्तर

21

कक्षा एक्सटेंशन का उपयोग करके आप निजी संपत्तियां प्राप्त कर सकते हैं।

एक वर्ग विस्तार वाक्य रचना सरल है:

@interface OverlayViewController : UIViewController <VSClickWheelViewDelegate> 
- (IBAction)moreButtonClicked:(id)sender; 
- (IBAction)cancelButtonClicked:(id)sender; 
@end 

मीटर:

मीटर फ़ाइल, वर्ग है कि अंदर, एक अज्ञात श्रेणी बना

#import "OverlayViewController.h" 

@interface OverlayViewController() 
@property(nonatomic) NSInteger amount; 
@property(retain,nonatomic)NSArray *colors; 
@end 

@implementation OverlayViewController 
@synthesize amount = amount_; 
@synthesize colors = colors_; 

//… 

@end 

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

ध्यान दें कि यह कोड संश्लेषित ivars का उपयोग करता है। हेडर में कोई इवर घोषणा की आवश्यकता नहीं है।

इस दृष्टिकोण के बारे में एक अच्छा cocoawithlove article है।

आप यह भी पूछते हैं कि निजी ivars के लिए गुणों का उपयोग क्यों करें।कई अच्छे कारण हैं:

  • गुण स्वामित्व और स्मृति प्रबंधन की देखभाल करते हैं।
  • भविष्य में किसी भी समय आप कस्टम गेटर/सेटर लिखने का निर्णय ले सकते हैं। यानी एनएसएआरएआरआई इवर नया सेट होने के बाद, एक टेबलव्यू पुनः लोड करने के लिए। यदि आपने परिणामस्वरूप गुणों का उपयोग किया है, तो अन्य परिवर्तनों की आवश्यकता नहीं है।
  • कुंजी मूल्य कोडिंग समर्थन गुण।
  • public readonly properties can be re-declared to private readwrite properties.

संपादित
LLVM 3 के बाद से यह भी संभव है, ivars वर्ग एक्सटेंशन में

@interface OverlayViewController(){ 
    NSInteger amount; 
    NSArray *colors; 
} 
@end 

या यहाँ तक कि कार्यान्वयन ब्लॉक

@implementation OverlayViewController{ 
    NSInteger amount; 
    NSArray *colors; 
} 
//… 
@end 

देखने पर घोषित करने के लिए "डब्ल्यूडब्ल्यूडीसी2011: सत्र 322 - उद्देश्य-सी एडवांसमेन गहराई में टीएस "(~ 03: 00)

+0

कुछ पेडेंट बताएंगे : वे सख्ती से निजी नहीं हैं क्योंकि गेटर्स और सेटर्स का उपयोग अभी भी अन्य कोड द्वारा किया जा सकता है यदि यह एक कंपाइलर चेतावनी बहादुर करने के इच्छुक है, लेकिन जहां तक ​​मुझे चिंता है कि संकलक चेतावनी दूसरों को चेतावनी देने के लिए पर्याप्त है। यह बिल्कुल सही तरीका है (ठीक है, अपने पिछला अंडरस्कोर दें या ले लो) मुझे अपनी टीम में आवृत्ति परिवर्तनीय घोषणा की आवश्यकता है - मैं जो नियम लागू करता हूं वह यह है कि हेडर फ़ाइल में कुछ भी परिभाषा द्वारा सार्वजनिक है। – Tommy

+0

@ टॉमी: मेरे काम पर, कुछ लोगों ने तर्क दिया, हमें निजी सदस्यों के लिए संपत्ति घोषित करने और उपयोग करने की आवश्यकता क्यों है। उन्होंने कहा कि हमें शुद्ध आवृत्ति चर का उपयोग करना चाहिए और उन्हें सीधे कक्षा कोड में उपयोग करना चाहिए। ऐसा करने के लिए प्रेरणा कुछ पुराने प्रसंस्करण मैन्युअल रूप से जारी करने और सीधे नए मूल्य को ivar को निर्दिष्ट करने के बजाय सेटटर का उपयोग करते समय कुछ प्रसंस्करण ओवरहेड था। बस उत्सुक हैं क्या कोई ऐप्पल उस पर बयान की तरह "अनुशंसित" है? – Centurion

+0

@Centurion आप "निजी" गुणों का उपयोग कर सकते हैं [मेमोरी प्रबंधन को आसान बनाते हैं] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/डॉक्टर/यूआईडी/टीपी 40004447-एसडब्ल्यू 4): "कभी-कभी यह थकाऊ या पैडेंटिक लग सकता है, लेकिन यदि आप लगातार एक्सेसर विधियों का उपयोग करते हैं, तो स्मृति प्रबंधन के साथ समस्याएं होने की संभावना काफी कम हो जाती है। यदि आप अपने पूरे दौरान इंस्टेंस वैरिएबल को बनाए रखने और रिलीज़ करने का उपयोग कर रहे हैं कोड, आप लगभग निश्चित रूप से गलत काम कर रहे हैं। " – albertamg

2

इसी प्रकार सी ++ के लिए, उद्देश्य सी सार्वजनिक, निजी और संरक्षित क्षेत्रों को प्रदान करता है। यह एक पैकेज स्कोप भी प्रदान करता है जो जावा में परिभाषित पैकेज स्कोप के समान है। कक्षाओं के सार्वजनिक चर कार्यक्रम में कहीं भी संदर्भ हो सकते हैं। निजी चर केवल कक्षा के संदेशों के संदर्भ में संदर्भित किया जा सकता है जो इसे घोषित करता है। इसका उपयोग उन संदेशों के भीतर किया जा सकता है जो एक ही कक्षा के किसी भी उदाहरण से संबंधित हैं। पैकेज स्कोप एक ही छवि के भीतर सार्वजनिक दायरे के समान है, यानी निष्पादन योग्य या पुस्तकालय। ऐप्पल के दस्तावेज़ीकरण के अनुसार, 64-बिट आर्किटेक्चर पर, एक अलग छवि के भीतर परिभाषित पैकेज स्कोप के चर को निजी के रूप में माना जाना चाहिए। परिवर्तनीय दायरा @public, @private, @ संरक्षित, @package modifiers द्वारा परिभाषित किया गया है। इन संशोधकों को सी ++ या जावा के समान तरीके से इस्तेमाल किया जा सकता है। एक स्कोप घोषणा के तहत सूचीबद्ध सभी चर एक ही दायरे से संबंधित हैं। साथ ही, वैरिएबल को उसी लाइन पर सूचीबद्ध किया जा सकता है जहां दायरा घोषित किया जाता है।

@interface VariableScope : NSObject { 
     @public 
     int iVar0; 
     @protected 
     int iVar1; 
     @private 
     int iVar2; 
     @package 
     int iVar3; 

@public int iVar01, iVar02; 
@protected int iVar11, iVar12; 
@private int iVar21, iVar22; 
@package int iVar31, iVar32; 
} 
    @end 

अधिक जानकारी के लिए नीचे दिए गए लिंक

http://cocoacast.com/?q=node/100

+4

हां, सार्वजनिक, निजी और संरक्षित जैसे कीवर्ड हैं, लेकिन वे रनटाइम के दौरान दायरे को सीमित नहीं करते हैं। मैंने कुछ परीक्षण किए हैं, और मैं कह सकता हूं कि उद्देश्य-सी में सभी सदस्य बहुत सार्वजनिक हैं। आप यहां मेरे प्रयोग के बारे में पोस्ट पा सकते हैं: http://stackoverflow.com/questions/6122398/objective-c-why-private-ivars-are-not-hidden-from-the-outside-access-when-using – Centurion

3

का उपयोग वास्तव में एक स्वच्छ, सुरक्षित, शून्य भूमि के ऊपर, जो सीधे भाषा के द्वारा समर्थित है इस का हल नहीं है। कई लोग वर्तमान दृश्यता सुविधाओं से संतुष्ट हैं, जबकि कई लोगों का मानना ​​है कि उनकी कमी है।

रनटाइम (लेकिन नहीं) इस भेद को ivars और विधियों के साथ बना सकता है। प्रथम श्रेणी का समर्थन सबसे अच्छा होगा, आईएमओ। - सब कुछ दिखाई दे रहा

विकल्प ए

बुरा है: तब तक, हम कुछ अमूर्त मुहावरों की है। मैं इस बात से सहमत नहीं हूं कि यह एक अच्छा दृष्टिकोण है, और यह ओओडी (आईएमओ) नहीं है।यदि सब कुछ दिखाई दे रहा है, तो अपने वर्ग चाहिए या तो:

  • समर्थन कैसे ग्राहक अपने वर्ग के लिए उपयोग कर सकते हैं सभी मामलों (आमतौर पर अनुचित या अवांछनीय)
  • या आप प्रलेखन के माध्यम से नियमों का एक टन के साथ उन्हें प्रदान (doc अद्यतन किसी का ध्यान नहीं जाने के लिए)
  • की संभावना है या accessors कोई साइड इफेक्ट होना चाहिए (OOD नहीं, और अक्सर 'accessors ओवरराइड नहीं करें')

विकल्प बी करने के लिए अनुवाद

0,123,

विकल्प ए की कमी है, और विकल्प ए की तरह, सदस्यों को कुंजी द्वारा एक्सेस किया जा सकता है।

विकल्प सी

यह थोड़ा सुरक्षित है। अन्य सभी की तरह, आप अभी भी कुंजी का उपयोग कर सकते हैं, और उप-वर्ग आपके एक्सेसर्स को ओवरराइड कर सकते हैं (भले ही अनजाने में)।

विकल्प डी

एक इस के लिए दृष्टिकोण एक कार्यान्वयन प्रकार से अधिक से अधिक एक आवरण के रूप में अपने वर्ग में लिखने के लिए है। आप इसके लिए ओबीजेसी प्रकार या सी ++ प्रकार का उपयोग कर सकते हैं। आप सी ++ का पक्ष ले सकते हैं जहां गति महत्वपूर्ण है (ओपी में इसका उल्लेख किया गया था)।

इस के लिए एक साधारण दृष्टिकोण रूपों में से एक ले जाएगा:

// inner ObjC type 
@class MONObjectImp; 

@interface MONObject : NSObject 
{ 
@private 
MONObjectImp * imp; 
} 
@end 


// Inner C++ type - Variant A 
class MONObjectImp { ... }; 

@interface MONObject : NSObject 
{ 
@private 
MONObjectImp imp; 
} 
@end 


// Inner C++ type - Variant B 
class MONObjectImp; 

@interface MONObject : NSObject 
{ 
@private 
MON::t_auto_pointer<MONObjectImp> imp; 
} 
@end 

(ध्यान दें:। चूंकि यह मूल रूप से लिखा गया था, @implementation ब्लॉक में ivars घोषित करने की क्षमता शुरू किया गया है आप घोषणा चाहिए अपने यदि पुराने टूलचेन्स या 'नाजुक' 32-बिट ओएस एक्स एबीआई का समर्थन करना आवश्यक नहीं है तो सी ++ प्रकार हैं।

सी ++ संस्करण ए दूसरों के रूप में 'सुरक्षित' नहीं है, क्योंकि इसे कक्षा की घोषणा क्लाइंट को दिखाई देती है। अन्य मामलों में, आप कार्यान्वयन फ़ाइल में आईपी कक्षा घोषित और परिभाषित कर सकते हैं - इसे ग्राहकों से छुपाएं।

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

ओबीजेसी कार्यान्वयन के लिए रनटाइम लागत एक नया प्रकार लिखना है, प्रत्येक उदाहरण के लिए एक नया छोटा सा उदाहरण बनाने के लिए, और मैसेजिंग की दोगुना राशि।

आवंटन (संस्करण बी) के अलावा सी ++ प्रकार का व्यावहारिक रूप से कुछ भी खर्च नहीं होगा।

विकल्प ई

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

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