views:

256

answers:

4

How can I create a method in the @implementation of a class without defining it in the @interface?

For example, I have a constructor that does some initialisation and then reads data from a file. I want to factor out the file-reading code into a separate method that I then call from within the constructor. I don't want to define this method in the header because it's private only to this @implementation context.

Is this possible?

Here's my example. I have a little program that read's a Todo task-list from a file.

Here is the @interface:

@interface TDTaskList : NSObject {
  NSString* name; // The name of this list.
  NSMutableArray* tasks;  // The set of tasks in this list.
}

-(id)initListOfName:(NSString*)aName;
-(NSArray*)loadListWithName:(NSString*)aName;

@end

And here is part of the @implementation:

-(id)initListOfName:(NSString*)aName {
  if (self = [super init]) {
    name = aName;

    NSArray* aTasks = [self loadListWithName:aName];
    tasks = [NSMutableArray arrayWithArray:aTasks];
  }

  return self;
}

-(NSArray*)loadListWithName:(NSString*)aName {
  // TODO This is a STUB till i figure out how to read/write from a file ...

  TDTask* task1 = [[TDTask alloc] initWithLabel:@"Get the Milk."];
  TDTask* task2 = [[TDTask alloc] initWithLabel:@"Do some homework."];

  return [NSArray arrayWithObjects:task1, task2, nil];
}

What I want to do is to not have to define the following in the interface:

-(NSArray*)loadListWithName:(NSString*)aName;
+2  A: 

You could use categories:

// In TDTaskList.m
@interface TDTaskList(TDTaskListPrivate)
-(id)initListOfName:(NSString*)aName;
-(NSArray*)loadListWithName:(NSString*)aName;
@end

@implementation TDTaskList(TDTaskListPrivate)

// implementation of initListOfName and loadListWithName ...

@end
Adam Rosenfield
Note that as of Objective-C 2.0 the category name is no longer required for private categories. This helps keep the code a bit simpler.
Andy
+5  A: 

As Andy hinted in the comments, you can use Extensions (which look like a category without a name). The difference is that you must implement the methods declared in an extension whereas the compiler doesn't verify that you implement methods declared in a category.

.h:

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

.m:

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

@implementation MyObject

- (NSNumber *)number
{
    return number;
}
- (void)setNumber:(NSNumber *)newNumber
{
    number = newNumber;
}
@end
Ryan E
+4  A: 

If you place the implementation of a method before any code that calls it you do not need to define it in the header.

So in this case put loadListWithName: in front of initListOfName: in the @implementation block and it will be good.

Note: Just because it is not defined in the header does not mean the method cannot be called by code outside of the object. Objective-C does not have private methods.

Nathan Kinsinger
This is the correct answer.
Max Howell
I see what you mean. So it's as if I'm writing a function outside the scope of this class, right?
gav.newalkar
+1  A: 
Till