7

I'm creating a category over NSDate. It has some utility methods, that shouldn't be part of the public interface.

How can I make them private?

I tend to use the "anonymous category" trick when creating private methods in a class:

@interface Foo()
@property(readwrite, copy) NSString *bar;
- (void) superSecretInternalSaucing;
@end

@implementation Foo
@synthesize bar;
.... must implement the two methods or compiler will warn ....
@end

but it doesn't seem to work inside another Category:

@interface NSDate_Comparing() // This won't work at all
@end

@implementation NSDate (NSDate_Comparing)

@end

What's the best way to have private methods in a Category?

cfischer
  • 24,452
  • 37
  • 131
  • 214
  • 2
    An "anonymous category" is actually called a "Class Extension". The major difference between a class extension and a category is that the `@implementation` of the class extension *must* be in the primary `@implementation` block of the class. – Dave DeLong Jun 25 '11 at 15:23

4 Answers4

4

It should be like this:

@interface NSDate ()

@end

@implementation NSDate (NSDate_Comparing)

@end
Paul Semionov
  • 491
  • 6
  • 17
2

I think the best way is to make another category in .m file. Example below:

APIClient+SignupInit.h

@interface APIClient (SignupInit)

- (void)methodIAddedAsACategory;
@end

and then in APIClient+SignupInit.m

@interface APIClient (SignupInit_Internal)
- (NSMutableURLRequest*)createRequestForMyMethod;
@end

@implementation APIClient (SignupInit)

- (void)methodIAddedAsACategory
{
    //category method impl goes here
}
@end

@implementation APIClient (SignupInit_Internal)
- (NSMutableURLRequest*)createRequestForMyMethod
{
    //private/helper method impl goes here
}

@end
Michał Zygar
  • 4,052
  • 1
  • 23
  • 36
  • I just tried this, and it doesn't work. Idk if it is because you didn't provide all code or something. Did you import anything special in the .m file? – coolcool1994 Jan 21 '18 at 21:50
2

It should be

@interface NSDate (NSDate_Comparing)

as in the @implementation. Whether or not you put the @interface in its own .h file is up to you, but most of the time you'd like to do this - as you want to reuse that category in several other classes/files.

Make sure to prefix your own methods to not interfere with existing method. or possible future enhancements.

Eiko
  • 25,601
  • 15
  • 56
  • 71
  • I get a warning complaining about: "Semantic Issue: Duplicate definition of category 'NSDate_Comparing' on interface 'NSDate'" – cfischer Jun 25 '11 at 15:33
  • Do you include it multiple times? Or maybe there already *exists* that category (try a different name)? – Eiko Jun 25 '11 at 16:30
  • 2
    I think @Fernando is putting two `@interface` blocks: one in the header file for the public methods and another one at the top of the implementation file intended for the "private" methods and this is causing the duplicate definition. – albertamg Jun 25 '11 at 18:24
  • Yes, exactly. That works fine with classes, is there a way to do it with Categories too? – cfischer Jun 26 '11 at 21:33
  • 5
    @Fernando Not including the "private" methods in the interface block and implementing them in the implementation block (above any calls to them) is not good enough? You could also declare them in a second category on `NSDate`, e.g. `@interface NSDate(NSDateComparingPrivate)` which would not be exposed as part of your API. – albertamg Jun 27 '11 at 14:00
-1

To avoid the warnings that the other proposed solutions have, you can just define the function but not declare it:

@interface NSSomeClass (someCategory) 
- (someType)someFunction;
@end

@implementation NSSomeClass (someCategory)

- (someType)someFunction
{
    return something + [self privateFunction];
}

#pragma mark Private

- (someType)privateFunction
{
    return someValue;
}

@end
Pwner
  • 3,714
  • 6
  • 41
  • 67
  • I think the OP asking this question because your solution doesn't work. When you have a Category class and have a method that is not declared in the .h file, you can't use it in the .m file. Why don't you try it because I just tried it, and it doesnt work. – coolcool1994 Jan 21 '18 at 21:47