Objective-C: Private Methods

July 2, 2008

Note: What follows is another post in an on-going series for developers who are interested in learning to write applications for the iPhone. The entire series can be found here: iPhone Developer .

One common complaint for many new to Objective-C is that the language lacks support for private methods within a class. There are compiler directives for instance variables: @private, @protected (the default) and @public. However, if you want to hide methods, there is no specific directives to help. The example here builds on the previous post on working with categories.

Ultimately, there is no means to make a method private in Objective-C. However, one can hide methods in a class as I show here. It’s important to understand, this still does not make the methods private, it just makes them “harder to find” if you will.

To implement hidden methods (instance and/or class) you can use categories . Let’s begin with a file called SomeClass.h, the interface definition for SomeClass.

// ===========================
// = File: SomeClass.h
// = Interface for SomeClass
// ===========================
 
@interface SomeClass : Object
 
-(void) msg;
+(void) classMsg; 
 
@end

Nothing too interesting here, simply an interface declaration for a class with two methods: msg and classMsg . By definition (of the language) both methods are publicly accessible. Now, let’s look at the corresponding implementation file shown below. Begin at the bottom where I write the implementation for the two methods above. Again, nothing new, so far. Now, if you start at the top of this file, notice how I’ve added an interface for SomeClass (similar to the interface definition above), however, I added (hidden) to the definition, which now makes the interface definition a category. Just below the definition, I write the code for the two methods in the category.

// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"
 
// =================================
// = Interface for hidden methods
// =================================
@interface SomeClass (hidden)
 
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod; 
 
@end
 
// =====================================
// = Implementation of hidden methods
// =====================================
@implementation SomeClass (hidden)
 
+(void) hiddenClassMethod
{
  printf( "Hidden class method.\n" );
}
 
-(void) hiddenInstanceMethod
{
  printf( "Hidden instance method\n" );
}
 
@end
 
// ================================
// = Implementation for SomeClass
// ================================
@implementation SomeClass
 
-(void) msg
{
  printf("Inside msg()...\n");
 
  [self hiddenInstanceMethod];
  [SomeClass hiddenClassMethod];
}
 
+(void) classMsg
{
  printf("Inside classMsg()...\n");
}
 
@end

To see what this does for us, look at the code below, followed by the screenshot:

// ===========================
// = File: Main.m
// ===========================
#import "SomeClass.h"
 
int main (int argc, char *argv[])
{
  SomeClass *ptr = [[SomeClass alloc] init];
 
  // Display message (including messages from hidden methods)
  [ptr msg];
 
  // Call a class method
  [SomeClass classMsg];
 
  // Compile warning (can't access hidden instance method)
//  [ptr hiddenInstanceMethod];
 
  // Compile warning (can't access hidden class method)
//  [SomeClass hiddenClassMethod];  
 
  return 0;
}

Notice how I can access the hidden instance and class methods from within the class. However, if I remove the comments from lines 17 and 20, to attempt access to the hidden methods, the compiler generates the following warnings:

I’m not sure if this is the only means to hide methods. If you know of another way (and have a code example), please post a comment.

The output of the application is shown here:

Download the code and give this a try within Xcode.

5 comments

Ondra (http://www.ocs.cz) has passed along another means to accomplish the same end result, without using categories:

@interface X:NSObject
-(void)published;
@end

@implementation X
-(void)unpublished { … }
-(void)published { … [self unpublished]; … }
@end

The trick here, is that the unpublished method is not defined in the interface, yet there is an implementation of the method in the implementation section. The end result here is that you don’t have two separate implementation sections.

I still prefer the idea of using categories as it make the implementation feel more akin to a publicly declared API (through SomeClass.h) and an additional (private) API for internal use by the class.

A personal preference to be sure…

by john on Jul 2, 2008 at 5:40 am. #

I prefer the category approach as well, mainly because I like to put “private” methods at the end, but I agree it’s a matter of preference. Note that Ondra’s approach only works if you can arrange your private methods in such a way that they are defined before they are called. In rare cases, private method X calls private method Y, and method Y also calls method X.

by Andy Lee on Jul 2, 2008 at 6:20 am. #

Change Main.m to include the following additional lines and the compiler warnings disappear. This is an unfortunately common pattern used to expose private API that oft produces maintenance headaches in the future.

#import “SomeClass.h”

@interface SomeClass (ExposingThePrivateParts)
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;
@end

int main (int argc, char *argv[])

by bob on Jul 2, 2008 at 6:53 am. #

An alternative way to declare a private class method is described in the Objective-C 2.0 documentation.

If you are writing your own class, you can add private methods that are implemented directly within the main implementation block of the class by declaring an empty category. eg:

@interface MyObject : NSObject
{
NSNumber *number;
}
- (NSNumber *)number;
@end

@interface MyObject ()
- (void)setNumber:(NSNumber *)newNumber;
@end

@implementation MyObject

- (NSNumber *)number
{
return number;
}
- (void)setNumber(NSNumber *)newNumber
{
number = newNumber;
}
@end

This way you don’t have to write a separate @implementation block for the private methods. Probably best to use this for methods that are only used within the class itself.

by stompy on Aug 15, 2008 at 2:25 am. #

Comments are closed on this post. You can comment on this same post which has been moved to the iPhone Developer Tips blog: http://iphonedevelopertips.com/objective-c/private-methods.html

by john on Aug 16, 2008 at 7:38 pm. #