112

What is the equivalent to protected methods in Objective-C? I want to define methods which only the derived classes may call/implement.

Dirty Henry
  • 6,978
  • 6
  • 48
  • 92
LK.
  • 4,361
  • 7
  • 34
  • 48

9 Answers9

156

You can simulate protected and private access to methods by doing the following:

  • Declare your private methods in a class extension (i.e. a unnamed category declared near the top of the class' .m file)
  • Declare your protected methods in a Subclass header – Apple uses this pattern with respect to UIGestureRecognizer (see documentation and reference to UIGestureRecognizerSubclass.h)

These protections are not, as Sachin noted, enforced at runtime (as they are in Java, for example).

Enrique
  • 785
  • 2
  • 6
  • 20
Brian Westphal
  • 5,559
  • 4
  • 20
  • 19
  • 2
    About the UIGestureRecognizer-like solution: The problem is that if some code imports the subclass it will also import the Subclass header and it will therefore have access to the "protected" methods. Is there a way around that? – yonix Feb 20 '12 at 10:44
  • 5
    Hi yonix, the import for the subclass header would be done inside of the .m file not inside of the .h file, so importing the subclass would't import these protected methods. – Brian Westphal Feb 22 '12 at 19:05
  • Cool Suggestion Brian, thanks a ton !! To the original poster, for declared properties, just ensure that you use @dynamic in the subclass's class extension (unnamed category) implementation, so that at runtime, the parent class's implementation would be used – user1046037 Feb 28 '12 at 12:49
  • 1
    How do I see UIGestureRecognizerSubclass.h? – user4234 Dec 03 '12 at 05:07
  • In Xcode, the easiest way is to use "Open Quickly" (⌘O) and then type UIGestureRecognizerSubclass.h. – Brian Westphal Dec 07 '12 at 01:12
  • why does the class use `@interface UIGestureRecognizer (ForSubclassEyesOnly)` instead of just `@interface UIGestureRecognizer ()`? Is that basically just another private interface? – jowie Jun 24 '13 at 09:23
  • The empty parentheses indicate a class continuation, rather than a category. Class continuations are special in that you can define properties to be synthesized. These have to be in the same files as the implementation, otherwise they're treated as categories. – Brian Westphal Sep 08 '13 at 20:46
  • 5
    Thanks for pointing out about how Apple does it internally. I [posted a full example](http://bootstragram.com/blog/simulating-protected-modifier-with-objective-c/) of how to implement stuff the same way Apple does in `UIGestureRecognizerSubclass.h` – Dirty Henry Mar 19 '14 at 17:02
  • Thank you Henry !! – gunjot singh Mar 14 '18 at 08:42
47

You can neither declare a method protected or private. Objective-C's dynamic nature makes it impossible to implement access controls for methods. (You could do it by heavily modifying the compiler or runtime, at a severe speed penalty, but for obvious reasons this is not done.)

Taken from Source.

Pang
  • 8,605
  • 144
  • 77
  • 113
Sachin Shanbhag
  • 50,935
  • 9
  • 84
  • 103
14

Here is what I did to get protected methods visible to my subclasses, without requiring them to implement the methods themselves. This meant I didn't get compiler warnings in my subclass about having an incomplete implementation.

SuperClassProtectedMethods.h (protocol file):

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

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m: (compiler will now force you to add protected methods)

#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.
Michael Kernahan
  • 1,420
  • 1
  • 13
  • 14
  • 2
    The meaning of *protected* is it is **not able** to be called externally. You still can call any methods defined in the class regardless of they are externally visible or not. – eonil Nov 19 '12 at 14:57
  • Yes, I understand this. This method works for the human brain, not actual compiled code. But Objective-C doesn't allow that (not being able to call externally). You can always `performSelector` on it. – Michael Kernahan Nov 19 '12 at 15:07
  • 1
    You also can do `[(id)obj hiddenMethod]`. Accurately saying, protected method is not supported in Objective-C. – eonil Nov 19 '12 at 15:20
  • The problem with this is that your so called protected classes cannot ad properties. If you do not need properties, then anyone is well aware that you can simply add protected categories. – user4234 Dec 03 '12 at 08:37
  • @eonil: "You also can do [(id)obj hiddenMethod]." Yes, you can do that, but you will get a warning from the compiler, if that method isn't in any included interface. – Kaiserludi Jun 19 '13 at 17:37
  • So this basically fulfills the purpose of the protected keyword: The compiler is telling the programmer of some unrelated class, that he is not supposed to use that method, so that programmer knows that when he actively ignores that warning, he is using undefined behavior and is relying on implementation details that could change without notice. If he then still insists to use that method, we also couldn't stop him in C++, where he could just do some hack like #define protected public before including the header of a class to access its protected methods from a non-subclass. – Kaiserludi Jun 19 '13 at 17:45
  • @Kaiserludi (1) Formally, Objective-C doesn't have method access control. (2) Inferred from Objective-C instance variable scope keyword, *protected* means access to the member is **allowed only to its subclasses**. With the method described in this answer, **any class** is allowed to access the method by importing the header. This cannot prohibit access from non-subclasses. – eonil Jun 20 '13 at 04:21
  • Of course, we can control `#import` manually, but that's just a manual control, not a *protected* method which means to be checked by compiler *over inheritance hierarchy*. This technique can be called *optional*, *hidden* or whatever, but not *protected* which is well-defined term. Because we cannot control importing header only to subclasses. (3) Abusing meta-programming feature to override language keyword semantics is different story just like a memory hack. – eonil Jun 20 '13 at 04:31
9

I just discovered this and it works for me.To improve upon Adam's answer, in your superclass make an implementation of the protected method in .m file but don't declare it in .h file. In your subclass make a new category in your .m file with the declaration of the protected method of the superclass and you can use the protected method of the superclass in your subclass. This will not ultimately prevent the caller of the supposedly protected method if forced at runtime.

/////// 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
redwud
  • 172
  • 3
  • 7
2

Another way using @protected variables.

@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
marius bardan
  • 4,397
  • 2
  • 26
  • 31
  • and you can put the protected IVars in a class extension in a header file named protected too – malhal Jul 08 '18 at 10:03
1

You can define the method as a private method of the parent class and can use [super performSelector:@selector(privateMethod)]; in the child class.

chinthakad
  • 851
  • 2
  • 16
  • 29
0

One option is to use class extension to hide methods.

In .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

In .m:

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

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end
Jadar
  • 1,567
  • 1
  • 11
  • 25
ohho
  • 47,708
  • 70
  • 236
  • 372
  • I don't think you even need the `@interface` declaration in the .m file. You can just declare a function and use it and it will treat is as private. – Russ Aug 20 '12 at 17:04
  • 1
    Note that this is true only with the recent updates in Objective C. Prior to that, you had to declare the method in an interface otherwise you'd at least get a warning. – Guillaume Laurent Aug 23 '12 at 07:36
0

You can sort of do this with a category.

@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

The methods aren't hidden if you import the category in another class, but you just don't. Due to the dynamic nature of Objective-C it's actually impossible to completely hide a method regardless of a calling instance type.

The best way to go is probably the class continuation category as answered by @Brian Westphal but you'll have to redefine the method in this category for each subclassed instance.

Adam Waite
  • 19,748
  • 19
  • 120
  • 146
0

I usually name protected method with internal prefix:

-(void) internalMethod;
lbsweek
  • 4,230
  • 37
  • 37