Fabrizio Prosperi
Fabrizio Prosperi

Reputation: 1398

Is it possible to declare a second @interface for a category?

I am trying to declare a private @interface for a category, in the .m file.

For a normal class I would do:

@interface ClassA ()

@end

@implementation ClassA

@end

and it would work smoothly.

For a class with categories I tried:

@interface ClassA (CategoryA) ()

@end

@implementation ClassA (CategoryA)

@end

but it is giving all sort of different errors. I am trying to "extend" a category, the way that a class is extended via this syntax @interface ClassA ().

I want to have private methods for the category, and I wanted to know if, IN ADDITION to the exposed interface I am allowed to put a second category @interface in the .m file, which does not expose instance variables and methods outside the class itself.

Something like this:

ClassA+categoryA.h

@interface ClassA (CategoryA)

<some public methods>

@end

ClassA+categoryA.m file

@interface ClassA (CategoryA)

<some private methods>

@end


@implementation ClassA (CategoryA)

<here I want to be able to call the private methods above>

@end

Right now this is giving me a warning in Xcode:

Duplicate definition of category 'CategoryA' on interface 'ClassA'

Is there any way to get this behavior?

Upvotes: 7

Views: 4082

Answers (3)

jscs
jscs

Reputation: 64012

No, you can't declare two interfaces for a single category. You can do one of two things:

Englebert+Humperdinck.h

#import "Englebert.h"

@interface Englebert (Humperdinck)

- (void) croon;

@end

You can declare another category with a different name to contain the private methods. These can then be used in the same file where the private category interface is declared:

Englebert+Humperdinck.m

#import "Englebert+Humperdinck.h"

@interface Englebert (HumperdinckPrivate)

- (void) warmUp;

@end

@implementation Englebert (HumperdinckPrivate)

- (void)warmUp {
    NSLog(@"Warm up");
}

@end

@implementation Englebert (Humperdinck)

- (void)croon {
    [self warmUp];
    NSLog(@"Croon");
    // etc.
}

@end

The other option is to simply not declare the private methods. If you just define them in the implementation block, you can use them at any point in that file after they are defined (and for the latest version of Xcode/LLVM, the order is in fact unimportant -- undeclared methods can be used anywhere in the file in which they are defined). No other files will be able to see these methods.

Englebert+Humperdinck.m

#import "Englebert+Humperdinck.h"

@implementation Englebert (Humperdinck)

/* Undeclared private method */
- (void)warmUp {
    NSLog(@"Warm up");
}

- (void)croon {
    [self warmUp];
    NSLog(@"Croon");
    // etc.
}

@end

Upvotes: 14

Aram Kocharyan
Aram Kocharyan

Reputation: 20431

@interface ClassA () is an anonymous category, and you can use these as interfaces and define the implementation in the ClassA implementation as well. @interface ClassA (CategoryA) () is a syntax error and should read @interface ClassA (CategoryA)

EDIT:

To create private methods for a class, in that class' .m file you would have:

@interface ClassA ()
    // Private functions declared
@end

@implementation ClassA
    // Private functions defined
    // Other functions defined
@end

The same can be done for named categories, however you will need to define the implementation separately to avoid warnings. Again, in the .m file:

@interface ClassA (hidden)
    // Private functions declared
@end

@implementation ClassA (hidden)
    // Private functions declared
@end

@implementation ClassA
    // Other functions defined
@end

Upvotes: 0

fbernardo
fbernardo

Reputation: 10124

Do

@interface ClassA (CategoryA)

@end

@implementation ClassA (CategoryA)

@end

Instead. Categories can't have instance varibles. And what kind of errors are you talking about?

Upvotes: 1

Related Questions