Created
March 7, 2012 19:51
-
-
Save BenedictC/1995580 to your computer and use it in GitHub Desktop.
Faking Protected Methods in Objective-C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.m | |
// Protected | |
// | |
// Created by Benedict Cohen on 07/03/2012. | |
// Copyright (c) 2012 __MyCompanyName__. All rights reserved. | |
// | |
// | |
// Unlike other object orientated languages Objective-C does not | |
// provide a mechanism for scoping methods as public, protected or private. | |
// In Objective-C all methods are essentially public. Private methods can be | |
// faked by declaring the methods within an anonymous @interface within the | |
// implementation file (i.e. the .m file). | |
// | |
// That only leaves protected methods. The common practice is to simply make | |
// a note in the documentation or in a comment that a method should be treated | |
// as protected. This approach isn't ideal because: | |
// - Not everyone reads the comments/documentation | |
// - Code can change and the comments/documentation not updated | |
// | |
// The following is a macro that allows protected methods to be annotated in | |
// the code. It's incredibly simple. It works by appending a string to the end | |
// of the method name. It also works with properties too. The intend is not to | |
// enforce method scope but to indicate the indent of a method. | |
/************************************* | |
The macro | |
This is the macro that does the magic. It's stupidly simple | |
The string is append not prepended so that setters remain sane | |
*************************************/ | |
#ifndef PROTECTED | |
#define PROTECTED(methodName) methodName ## _protected | |
#endif | |
/************************************* | |
BaseClass | |
This is the base class that has some protected methods | |
*************************************/ | |
#import <Foundation/Foundation.h> | |
@interface BaseClass : NSObject | |
//a protected method. Note that the colon is outside of the macro. | |
-(void)PROTECTED(aProtectedMethod):(id)withAnArgument; | |
//a protected property. | |
@property(readwrite, nonatomic, strong) NSString * PROTECTED(aName); | |
@end | |
@implementation BaseClass | |
//implmenting a protected method | |
-(void)PROTECTED(aProtectedMethod):(id)withAnArgument | |
{ | |
NSLog(@"%@ - %@", [self className], NSStringFromSelector(_cmd)); | |
} | |
//implementing a protected property. Note that we are still specifing the name of the ivar to use to the property. | |
@synthesize PROTECTED(aName) = _aName; | |
@end | |
/************************************* | |
SubClass | |
This is the subclass which will access the protected methods | |
*************************************/ | |
@interface SubClass : BaseClass | |
//Nothing special about these declarations | |
-(void)callSuperProtected; | |
//this is simple exposing supers protected method | |
@property(readonly) NSString *aName; | |
@end | |
@implementation SubClass | |
-(void)callSuperProtected | |
{ | |
//Calling a protected method on super. Again, note that the colon is outside of the macro. | |
[super PROTECTED(aProtectedMethod):nil]; | |
} | |
-(NSString *)aName | |
{ | |
//It works with dot syntax too! (OK, this does look weird). | |
return super.PROTECTED(aName); | |
} | |
@end | |
/************************************* | |
Other calling examples | |
*************************************/ | |
int main(int argc, const char * argv[]) | |
{ | |
@autoreleasepool { | |
//This line will not compile due to a 'method not found' error | |
//[[BaseClass new] aProtectedMethod:nil]; | |
//Code-completion will still suggest the protected methods but they will be | |
//displayed as 'aProtectedMethod_protected:' so it's clear what there purpose is. | |
//This line will compile | |
[[BaseClass new] aProtectedMethod_protected:nil]; | |
//This line will compile | |
[[SubClass new] callSuperProtected]; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment