10

I'm aware that Objective-C doesn't support real private methods. What I'm currently doing to declare 'private' methods is adding the following to class .m files:

@interface MyClass() 

- (void) privateMethodName;

@end


The Problem:

If I now add a subclass, and want to use this 'private' method, I can't! I get the error:

Receiver type 'SubClassName' for instance message does not declare a method with selector 'privateMethodName'


So, if I don't want non-subclasses to be able to access this method, but do want subclasses to be able to, what can I do? What is the best/proper way of achieving my goal?

Jordan Smith
  • 10,310
  • 7
  • 68
  • 114
  • 2
    The simple solution is to not make them private. Is anyone else going to use your code? Do you think you really need that level of control? – pe8ter Jan 06 '12 at 09:20
  • 3
    I'm with Jordan here: not every method should go into a class's public header file — it just adds noise, and most of the time you really don't want anybody outside messing with your internal helpers... – danyowdee Jan 06 '12 at 09:25
  • 2
    @pe8ter even if you work alone, this level of control definitely helps. it is foolish to believe you've (accurately) memorized hundreds of thousands of lines of code. – justin Jan 06 '12 at 09:29
  • 2
    @pe8ter I'd rather do things the clean way if possible :) If anyone else was ever going to modify my code, using the method outside of a subclass would result in confusing and complex code. – Jordan Smith Jan 06 '12 at 09:32

3 Answers3

16

You could separate the "protected" interface from the public one. In the primary header, just declare the public methods:

MyMagicThingy.h:

@interface MyMagicThingy: NSObject

- (void) publicMethod;

@end 

Then, have an additional header with protected methods:

MyMagicThingy+Protected.h:

#import "MyMagicThingy.h"

@interface MyMagicThingy (Protected)

- (void) protectedMethods;

@end

You cannot have "real" private/protected/public methods in Objective C (as in: the compiler will enforce access rules. All methods are public). You have to go with a convention.

Dirk
  • 30,623
  • 8
  • 82
  • 102
  • +1 this is perhaps my favorite general solution to the problem in strictly ObjC contexts. It's the same answer I made, with a nice example. – justin Jan 06 '12 at 09:26
  • Ahh, I've seen protected interfaces before but never realized what they actually did. Thanks! – Jordan Smith Jan 06 '12 at 09:35
2

What you describe is really a protected method. One approach to overcome this: Ivars can be declared @public, @protected, or @private. You could declare a protected helper instance to restrict access to derived instances, which then calls back through the object which holds it.

Another alternative in some cases would be to make the subclasses write to an interface, then keep your implementation private.

Sometimes, you just have to document "don't do this, unless you are not a subclass" because it's not part of the language. In this mindset, a separate header which declares a category of protected methods is one of my favorite. It's pretty well hidden from clients, but can be made visible to subclasses by explicit inclusion -- Dirk provided an example of this at the same time, check it out.

Lastly, if you're comfortable with ObjC++, C++ offers this control, so you can mix modes and visibility quite freely.

justin
  • 104,054
  • 14
  • 179
  • 226
0

First and foremost

You can't get anyone to not being able to call any method that is implemented on an object in Objective-C (at least not without burning through several dozen razors making Yaks less weatherproof).

Just don't call methods that are not declared in public header files, as a convention (this is, what you're already doing).

Second

The word public in the above paragraph does the trick:

In Objective-C (at least in its current incarnation), a class's interface can be defined over any number of header files using the technique you just described in your post: Class continuations.

One such example of an Apple framework class doing that would be UIGestureRecognizer with its separate subclassing header UIGestureRecognizerSubclass.h.


PS:
The error you are seeing reeks of using ARC so your runtime is definitely recent enough to even use multiple implementation files for that.

danyowdee
  • 4,658
  • 2
  • 20
  • 35