उद्देश्य-सी में संरक्षित तरीके


112

उद्देश्य-सी में संरक्षित विधियों के समतुल्य क्या है? मैं उन तरीकों को परिभाषित करना चाहता हूं जो केवल व्युत्पन्न वर्ग कॉल / लागू कर सकते हैं।

जवाबों:


47

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

सोर्स से लिया गया ।


तकनीकी रूप से आप नहीं कर सकते, आप निजी चर का अनुकरण कर सकते हैं।
शेरेन इयर्स

ली - यदि आप @protected में एक फंक्शन पॉइंटर घोषित करते हैं और एक फंक्शन को असाइन करते हैं तो यह काम करेगा?
bikram990

156

आप निम्न करके विधियों में संरक्षित और निजी पहुँच का अनुकरण कर सकते हैं :

  • कक्षा विस्तार में अपनी निजी विधियों की घोषणा करें (अर्थात कक्षा के शीर्ष के पास घोषित अनाम श्रेणी)।
  • Subclass हैडर में अपनी संरक्षित विधियों की घोषणा करें - Apple UIGestureRecognizer (UIGestureRecognizerSubclass.h पर प्रलेखन और संदर्भ देखें) के संबंध में इस पैटर्न का उपयोग करता है

ये सुरक्षा नहीं हैं, जैसा कि सचिन ने उल्लेख किया है, रनटाइम पर लागू किया गया है (जैसा कि वे जावा में हैं, उदाहरण के लिए)।


2
UIGestureRecognizer- जैसे समाधान के बारे में: समस्या यह है कि यदि कुछ कोड उप-वर्ग का आयात करता है तो यह उप-वर्ग शीर्षक को भी आयात करेगा और इसलिए इसकी "संरक्षित" विधियों तक पहुंच होगी। क्या इसके आसपास कोई रास्ता है?
yonix

5
हाय yonix, सबक्लास हेडर के लिए आयात। M फ़ाइल के अंदर .h फ़ाइल के अंदर नहीं किया जाएगा, इसलिए सबक्लास का आयात इन संरक्षित तरीकों को आयात नहीं करेगा।
ब्रायन वेस्टफेल

कूल सुझाव ब्रायन, एक टन धन्यवाद !! घोषित संपत्तियों के लिए, मूल पोस्टर के लिए, बस यह सुनिश्चित करें कि आप उपवर्ग के वर्ग विस्तार (अनाम श्रेणी) कार्यान्वयन में
@dynamic का

1
मैं UIGestureRecognizerSubclass.h कैसे देख सकता हूँ?
शेरेन इयर्स

5
एप्पल आंतरिक रूप से कैसे करता है, इसके बारे में बताने के लिए धन्यवाद। मैंने एक पूर्ण उदाहरण पोस्ट किया कि सामान को कैसे लागू किया जाए जिस तरह से Apple करता हैUIGestureRecognizerSubclass.h
डर्टी हेनरी

14

यहाँ है कि मैंने अपने उपवर्गों को दिखाई देने वाले संरक्षित तरीकों को प्राप्त करने के लिए क्या किया, बिना उन्हें खुद को लागू करने के तरीकों की आवश्यकता के। इसका मतलब था कि मुझे अधूरा कार्यान्वयन होने के बारे में मेरे उपवर्ग में संकलक चेतावनी नहीं मिली।

SuperClassProtectedMethods.h (प्रोटोकॉल फ़ाइल):

@protocol SuperClassProtectedMethods <NSObject>
- (void) protectMethod:(NSObject *)foo;
@end

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m: (कंपाइलर अब आपको संरक्षित तरीके जोड़ने के लिए बाध्य करेगा)

#import "SuperClassProtectedMethods.h"
@implementation SuperClass
- (void) protectedMethod:(NSObject *)foo {}
@end

SubClass.m:

#import "SuperClassProtectedMethods.h"
// Subclass can now call the protected methods, but no external classes importing .h files will be able to see the protected methods.

2
संरक्षित का अर्थ यह है कि बाहरी रूप से बुलाया जाने में सक्षम नहीं है । आप अभी भी कक्षा में परिभाषित किसी भी तरीके को कॉल कर सकते हैं, भले ही वे बाहरी रूप से दिखाई दें या नहीं।
eonil

हां, मैं यह समझता हूं। यह विधि मानव मस्तिष्क के लिए काम करती है, वास्तविक संकलित कोड के लिए नहीं। लेकिन ऑब्जेक्टिव-सी इसकी अनुमति नहीं देता (बाहरी रूप से कॉल करने में सक्षम नहीं)। आप हमेशा इस performSelectorपर रह सकते हैं ।
माइकल कर्नाहन

1
आप भी कर सकते हैं [(id)obj hiddenMethod]। सटीक रूप से कहा गया है, ऑब्जेक्टिव-सी में संरक्षित पद्धति का समर्थन नहीं किया गया है।
eonil

इसके साथ समस्या यह है कि आपके तथाकथित संरक्षित वर्ग गुणों का विज्ञापन नहीं कर सकते हैं। यदि आपको संपत्तियों की आवश्यकता नहीं है, तो किसी को अच्छी तरह से पता है कि आप केवल संरक्षित श्रेणियां जोड़ सकते हैं।
शरन ईयर्स

@ ओनोइल: "आप भी कर सकते हैं [(आईडी) ओब्जेक्ट हिडनमैथोड]।" हां, आप ऐसा कर सकते हैं, लेकिन आपको कंपाइलर से एक चेतावनी मिलेगी, यदि वह विधि किसी भी सम्मिलित इंटरफ़ेस में नहीं है।
कैसरलुडी

9

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

/////// SuperClass.h
@interface SuperClass

@end

/////// SuperClass.m
@implementation SuperClass
- (void) protectedMethod
{}
@end

/////// SubClass.h
@interface SubClass : SuperClass
@end

/////// SubClass.m
@interface SubClass (Protected)
- (void) protectedMethod ;
@end

@implementation SubClass
- (void) callerOfProtectedMethod
{
  [self protectedMethod] ; // this will not generate warning
} 
@end

2
इस मामले में संकलक अभी भी protectedMethod
अनिमित

यह चारों ओर एक अच्छा काम है लेकिन एक श्रेणी (संरक्षित) बनाने के बजाय, आप एक विस्तार कर सकते हैं।
धर्मेश सिद्धपुरा

@skywinder शायद यह पहले के संस्करण में किया था, लेकिन Xcode के वर्तमान संस्करणों को इस समाधान के साथ कोई समस्या नहीं है।
डैरेन एहलर्स

2

एक और तरीका @protected वैरिएबल का उपयोग कर रहा है।

@interface SuperClass:NSObject{
  @protected
    SEL protectedMehodSelector;
}

- (void) hackIt;
@end

@implementation SuperClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(baseHandling);
 }

return self;
}

- (void) baseHandling {

  // execute your code here
}

-(void) hackIt {

  [self performSelector: protectedMethodSelector];
}

@end

@interface SubClass:SuperClass
@end

@implementation SubClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(customHandling);
 }

return self;
}

- (void) customHandling {

  // execute your custom code here
}

@end

और आप संरक्षित IVars को एक क्लास एक्सटेंशन में संरक्षित शीर्षक में रख सकते हैं जिसका नाम भी संरक्षित है
malhal

1

आप पैरेंट क्लास के एक निजी तरीके के रूप में विधि को परिभाषित कर सकते हैं और [super performSelector:@selector(privateMethod)];चाइल्ड क्लास में उपयोग कर सकते हैं ।


0

आप कर सकते हैं एक तरह से एक वर्ग के साथ ऐसा कर।

@interface SomeClass (Protected)
-(void)doMadProtectedThings;
@end

@implementation SomeClass (Protected)

- (void)doMadProtectedThings{
    NSLog(@"As long as the .h isn't imported into a class of completely different family, these methods will never be seen. You have to import this header into the subclasses of the super instance though.");
}

@end

यदि आप श्रेणी को किसी अन्य वर्ग में आयात करते हैं तो विधियाँ छिपी नहीं हैं, लेकिन आप अभी नहीं हैं। ऑब्जेक्टिव-सी की गतिशील प्रकृति के कारण एक कॉलिंग प्रकार की परवाह किए बिना एक विधि को पूरी तरह से छिपाना वास्तव में असंभव है।

जाने का सबसे अच्छा तरीका शायद वर्ग निरंतरता श्रेणी है जैसा कि @Brian Westphal द्वारा उत्तर दिया गया है, लेकिन आपको प्रत्येक उपवर्गित उदाहरण के लिए इस श्रेणी में विधि को फिर से परिभाषित करना होगा।


0

एक विकल्प तरीकों को छिपाने के लिए वर्ग विस्तार का उपयोग करना है।

में .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

में .m:

@interface SomeAppDelegate()
- (void)localMethod;
@end

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end

मुझे नहीं लगता कि आपको @interface.m फ़ाइल में घोषणा की भी आवश्यकता है । आप केवल एक फ़ंक्शन की घोषणा कर सकते हैं और इसका उपयोग कर सकते हैं और यह इलाज निजी है।
रसेल

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

0

मैं आमतौर पर आंतरिक उपसर्ग के साथ संरक्षित विधि का नाम देता हूं:

-(void) internalMethod;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.