Protected methods in Objective-C - objective-c

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

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).

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.

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.

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

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

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

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.

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

I usually name protected method with internal prefix:
-(void) internalMethod;

Related

Call method with instance creator as receiver

I have class A, (NSDocument subclass) which stores my document data. Class A creates an instance of Class B, (NSView subclass) which manages the view. I want it so that every time the drawRect: method of Class B is called, it calls updateChangeCount: on Class A so that the user will know to save the document.
I'm not completely familiar with OSX projects and what exactly drawRect: does for NSView, so you may want to look into Richard J Ross III's comment. But on the general question of one object calling a method on the object that instantiated it:
ClassB.h
#protocol ClassBDelegate <NSObject>
#reqiured
- (void)someRequiredMethod;
#optional
- (void)someOptionalMethod;
#end
#interface ClassB <NSView>
#property (nonatomic, assign) id<ClassBDelegate> delegate;
// Other stuff you need in your interface
#end
ClassB.m
- (void)someClassBMethodThatNeedsToTriggerSomeClassAMethod {
// stuff
[self.delegate someRequiredMethod];
if ([self.delegate respondsToSelector:#selector(someOptionalMethod)]) {
[self.delegate someOptionalMethod];
}
// stuff
}
Now, in ClassA, be sure you conform to this protocol:
#import ClassB.h
#interface ClassA <ClassBDelegate>
And implement the required method:
- (void)someRequiredMethod {
// stuff
NSLog(#"Hello world!");
// stuff
}
And when you instantiate your ClassB object, be sure to set its delegate to yourself:
classB.delegate = self;
EDIT: Note, I put in an example of how ClassB can use optional methods as well as required methods.

Private methods in objective-c not private

I've created two classes with methods with same name. In one of them it is private, in another - public.
Then somewhere on code i write this:
-(void) doMagic:(id) object {
[(ClassA*)object doSmth];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
ClassB * objB = [[ClassB alloc] init];
[self doMagic:objB];
}
In console i see this:
2012-04-25 23:41:28.183 testmagic[558:403] classB - doSmth
Here's classes' sources:
//.h
#interface ClassA : NSObject
-(void) doSmth;
#end
//.m
#implementation ClassA
-(void)doSmth {
NSLog(#"classA - doSmth");
}
#end
//.h
#interface ClassB : NSObject
#end
//.m
#interface ClassB ()
-(void) doSmth;
#end;
#implementation ClassB
- (void)doSmth {
NSLog(#"classB - doSmth");
}
#end
I know, it's because of "message" nature of methods in Obj-C, and at runtime class possibly do not know which of it's methods are private or public, but here's the question:
How can i make really private method? I heard that with decompiling it's possible to see methods names, so someone can just use my private API. How can i prevent it?
The runtime cannot call what it never knows about. The approach I typically take is to use a static function:
MONObject.h
#interface MONObject : NSObject
// ...
#end
MONObject.m
// 'private' methods and ivars are also visible here
#interface MONObject()
// ...
#end
// typically here:
static void fn(MONObject * const self) {
NSLog(#"%#", [self description]);
}
#implementation MONObject
// ...
// sometimes here:
static void fn2(MONObject * const self) {
NSLog(#"%#", [self description]);
}
#end
A workaround to your problem could be to use a proxy/façade class which internally aggregates an instance of your private class. E.g.:
// .h
#interface FoobarFacade: NSObject
- (void)publicMethod;
#end
// .m
#interface FoobarFacade ()
{
Foobar* impl;
}
#end
#interface Foobar: NSObject
- (void)secretMethod;
#end
#implementation Foobar
- (void)secretMethod { NSLog(#"foobar secret method"); }
#end
#implementation FoobarFacade
- (void)publicMethod {
NSLog(#"façade public method");
[impl secretMethod]; // calling into the secret method
}
#end
Of course this isn't 100% safe either, the runtime puts no barriers as others already told.
Right now you can't have truly private methods. When you are declaring a method in a class extension in the .m file you are just hiding it from being exposed in the public header fle. What you are doing now is considered good design because you are hiding the method from the header file which means people would have to go to some length to find those hidden methods, but they can still find them.
Basically the rule I follow is to put as little as I can into the public header as possible and to put everything else into a class extension. This is all you can really do for now.
If you declare the method in the .h file is public. If you want private visibility you have to declare the method in your .m for example:
#interface ClassB (Private_Methods)
- (void)doSmth;
#end
#implementation ClassB
//Rest of .m

Reference properteries declared in a protocol and implemented in the anonymous category?

I have the following protocol:
#protocol MyProtocol
#property (nonatomic, retain) NSObject *myProtocolProperty;
-(void) myProtocolMethod;
#end
and I have the following class:
#interface MyClass : NSObject {
}
#end
I have a class extension declared, I have to redeclare my protocol properties here or else I can't implement them with the rest of my class.
#interface()<MyProtocol>
#property (nonatomic, retain) NSObject *myExtensionProperty;
/*
* This redeclaration is required or my #synthesize myProtocolProperty fails
*/
#property (nonatomic, retain) NSObject *myProtocolProperty;
- (void) myExtensionMethod;
#end
#implementation MyClass
#synthesize myProtocolProperty = _myProtocolProperty;
#synthesize myExtensionProperty = _myExtensionProperty;
- (void) myProtocolMethod {
}
- (void) myExtensionMethod {
}
- (void) useMyConsumer {
[[[MyConsumer new] autorelease] consumeMyClassWithMyProtocol:self];
}
#end
MyConsumer will only be called from MyClass, so I don't want any other classes to see that MyClass implements methods on MyProtocol because they aren't public API. Similarly, I don't want MyConsumer to see the class extension within MyClass.
#interface MyConsumer : NSObject {
}
#end
#implementation MyConsumer
- (void) consumeMyClassWithMyProtocol: (MyClass<MyProtocol> *) myClassWithMyProtocol {
myClassWithMyProtocol.myProtocolProperty; // works, yay!
[myClassWithMyProtocol myProtocolMethod]; // works, yay!
myClassWithMyProtocol.myExtensionProperty; // compiler error, yay!
[myClassWithMyProtocol myExtensionMethod]; // compiler warning, yay!
}
#end
Is there any way I can avoid redeclaring the properties in MyProtocol within my class extension in order to implement MyProtocol privately?
What you've been referring to as an "anonymous category" is actually known as a class extension, and is used to declare private functionality in an implementation file. That last part is important, because it means that other classes will not be able to see the declarations that you put into a class extension (and they won't be able to see that your class implements the methods of MyProtocol). This is also probably what is responsible for #synthesize failing without redeclaring the properties.
Instead, declare your conformance to the protocol in the interface of your class, and add whatever methods you want to be public:
#interface MyClass : NSObject <MyProtocol> {
}
// public methods and properties go here
#end
If you add the protocol declaration to your interface, then it also removes the need for your consumer to specify it explicitly. Your consumer method can have the following signature instead:
- (void) consumeMyClassWithMyProtocol: (MyClass *) myClassWithMyProtocol;
EDIT: It sounds like you're looking for a way to selectively expose private functionality. First, I would try to consider a different architecture for what you're trying to accomplish, because what's about to follow is a rather unpleasant solution, and it's generally better OOP if everything is public or private.
With that said, Apple typically solves this problem by having a separate header file for the class in question, which declares the methods that should be visible. So you would have your class interface, in which you expose everything that should be completely public:
// MyClass.h
#interface MyClass : NSObject {
}
#end
And a separate header, in which you declare a category for pseudo-private stuff:
// MyClass+Private.h
#import "MyClass.h"
#interface MyClass (Private) <MyProtocol>
- (void)mySortaPrivateMethod;
#end
MyClass.m would implement everything from those two files, and could still have a class extension:
// MyClass.m
#import "MyClass.h"
#import "MyClass+Private.h"
#interface MyClass ()
- (void)myClassExtensionMethod;
#end
#implementation MyClass
// everything can go here
#end
Then your consumer would include MyClass+Private.h so that it can see the declarations there, and everyone else would simply use MyClass.h.

Objective-C : How may I hide a class member from outside the class?

I'm fighting with something and I don't find any satisfying solution.
I have a class with a "myMutableArray" member.
I would like the class to manage itself adding and removing items from the array, so I don't want any other class being able to access the member and call NSMutableArray methods on it.
In an ideal situation, I would like to have a private getter (to be able to call self.myMutableArray) and a public setter for this member.
Do you know how I may achieve this ?
In other words :
I would like other classes
be able to call
- [oneInstance setMyMutableArray:thisArray]; // set
- oneInstance.myMutableArray = thisArray; // set using setter
- thisArray = oneInstance.myMutableArray; // get
- [oneInstance addItem:anItem]; // add
not being able to call :
- [oneInstance.myMutableArray add:etc...] // add
I would like my class
be able to call
- self.myMytableArray = [NSMutableArray array]; // set
- thisArray = self.myMytableArray ; // get
Thank you.
Is there any reason you need the public setter? It sounds like the class itself owns the array. You'd probably be better off not providing any public property access to the field, and making a public method which copies the values into your private field.
// public interface, in the .h file
#interface MyClass : // superclass, protocols, etc.
- (void) setSomething:(NSArray *)values;
#end
// private interface, not in the .h
#interface MyClass ()
#property (/* attributes */) NSMutableArray *myMutableArray;
#end
#implementation MyClass
#synthesize myMutableArray = myMutableArray_;
- (void) setSomething:(NSArray *)values
{
[self.myMutableArray setArray:values];
}
#end
Foo.h
#interface Foo : NSObject
#property(readonly, retain) NSArray * myReadonlyArray;
- (void) addItem: (Item *) anItem;
- (BOOL) publiclyDoSomething;
#end
Foo.m
#interface Foo()
#property(readwrite, retain) NSMutableArray * myMutableArray;
- (void) doSomethingInPrivate;
#end
#implementation Foo
#synthesize myMutableArray = myMutableArray_;
- (void) addItem: (Item *) anItem
{
// assuming myMutableArray_ was already iniitialized
[self.myMutableArray addObject: anItem];
}
- (NSArray *)myReadonlyArray
{
return self.myMutableArray;
}
... rest of methods (including the public/private) implementations ...
#end
Some details:
Objective-C has "instance variables", not "member variables".
The above defines a public getter and private setter that is synthesized automatically. For clarity's sake, I also added a public method and a private method.
"Public" and "private" in Objective-C are defined entirely by visibility to the compiler. The setter for myMutableArray and the method doSomethingInPrivate are only private because their declarations in an #interface cannot be imported.
self.myMutableArray and [self myMutableArray] do the same thing; the . syntax is merely short hand for an equivalent method call (with a few edge case details beyond this question)
#property in the #interface is purely short hand for method declarations (with a bit of extra metadata).
#interface Foo() is a class extension and not a category. It exists for exactly the purpose demonstrated above; to extend the #interface of a class with additional declarative information whose scope should be limited. It can appear in a header file that, say, you only import in your library's implementation to create library-private functionality.
#dynamic is used when you neither #synthesize an #property nor provide a conventional method implementation. It is not needed otherwise!
I'm probably forgetting something.

how to make a single method in a class to private in Objective-c?

how to make a single method in a class to private in Objective-c?
There's no concept of private methods in Objective-C. What you can do, however, is obmitting the method in the header file and adding a category in a private file.
Usually this is down like this:
#interface MyObject : NSObject {
// ivars
}
// public methods
#end
// usually in a seperate file
#interface MyObject ()
// private methods
#end
An empty name for a category means that it's a class extension, this tells the compiler that the method is required in the main implementation block.
You can't strictly speaking create private methods in Objective-C; but you can create a category in the file containg the implementation (MyClass.m), hiding it from the header file (MyClass.h).
//MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject {
}
#end
Implementation file:
//MyClass.m
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod {
return;
}
#end
Objective-C doesn't support private methods natively by design.
However, you can achieve private method control by using "class extensions" (anonymous categories).
The basic idea is to declare a class extension with your private methods inside the implementation file for your class (not its header), but outside of your #implementation block. You can then implement the methods and no outside class will be able to see them. Like this:
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod
{
//implementation goes here
}
-(void)someOtherMethod
{
[self myPrivateMethod];
}
#end
Using a class extension forces you to implement the methods in the main #implementation block and requires that they are implemented (much like as if they were declared in the main #interface block in the header).
Unfortunately, due to Objective-C's dynamic nature, this won't actually prevent those methods from being called by other classes. They will get a warning telling them that the class may not respond to the message, but at runtime it will work. The only thing this gives you is the ability to hide the methods from other programmers.
You can't. Only instance variables can be marked as private.
Though there are ways to do something equivalent to private methods.
The general idea is that you don't declare the private method in your header but in your implementation file.
Therefore, if you'd want to have a public (myPublicMethod) and private (myPrivateMethod) method, you're header could look like this:
#interface MyClass {
}
- (void)myPublicMethod;
#end
And then you have three options for your implementation file:
1.
Don't declare the method in any #interface section and just make sure it's implemented before it's being used in the #implementation section.
#implementation MyClass
- (void)myPrivateMethod { }
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end
2.
Use an anonymous category in your implementation file to declare the private methods and implement them in the main #implementation block.
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod { }
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end
3.
Use a regular category in your implementation file and implement the private methods in a separate #implementation block.
#interface MyClass (PrivateMethods)
- (void)myPrivateMethod;
#end
#implementation MyClass (PrivateMethods)
- (void)myPrivateMethod { }
#end
#implementation MyClass
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end