27

I'm trying to create a factory (design pattern) in Objective C So I'm doing something like:

+ (Car *)createCar:(int)color {
    if (color == 1) {
        return [CarFactory createBlueCar];
    } else if (color == 2) {
        return [CarFactory createRedCar];
    } else {
        return nil;
    }
}

+ (Car *)createBlueCar {
    // ...
}

+(Car*)createRedCar{
    // ...
}

However I don't want the createBlueCar and the createRedCar to be available to public and if I don't define them in the .h file then I get a warning of the missing definition.

I'm a former Java developer and a newbie in Objective-C — So it might be just bad practice If so what the be good practice of doing so.

3
  • 2
    You usually don't have Factory classes in Objective-C since classes are first class objects. Look at Umbrella classes such as NSPredicate or NSNumber. They are factories. You will usually get a subclass of NSPredicate or NSNumber returned. Commented Feb 14, 2014 at 12:39
  • 2
    Agree with @AdamSmith, the best way to do it would be a class method on Car, e.g. +(Car *)carWithColor:(int)color;
    – dmur
    Commented Jul 9, 2014 at 0:12
  • Actually I noticed another thing which might not be clear when comming from Java. If "createCar" is on CarFactory class best practice is usually to write [self createBlueCar]. In ObjC classes are objects unlike Java. So self in a class method refers to the class object (CarFactory in this case). The reason for using "self" is that code will not break if you inherit "CarFactory" and reimplement e.g. "createBlueCar" Commented Jul 9, 2014 at 10:51

3 Answers 3

49

The best way to do this is with a Class Extension.

.h

@interface MyClass : NSObject
@property(readonly) BOOL publiclyReadOnlyPrivatelyWritableFlag;
+ (id) myExposedFactoryMethod;
@end

.m

#import "MyClass.h"

@interface MyClass ()
@property(readwrite) BOOL publiclyReadOnlyPrivatelyWritableFlag;
+ (id) privateMethod1;
+ (id) privateMEthod2;
@end

@implementation MyClass
@synthesize publiclyReadOnlyPrivatelyWritableFlag; // no ivar -- only works in 64 bit and iPhone
+ (id) myExposedFactoryMethod
{
    ...
    [self privateMethod1];
    ...
}

+ (id) privateMethod1;
{
    return ...
}

+ (id) privateMEthod2;
{
    return ...
}
@end

A class extension is a better solution because it is a true extension of the class's interface whereas a category (without a corresponding implementation) is merely a suggestion that the class implement the methods. That is, the compiler will warn if you don't implement the interface -- the methods -- declared in the class extension, but will not warn if you did the same with a named category.

Note also that a class extension allows you to upgrade a readonly property to a readwrite property as per the above example.

1
  • 2
    +1 This should really be the accepted answer, since it demonstrates how to do it and precisely why. Commented Jan 20, 2010 at 20:51
4

I think you can add them to the class using an objective-c category within the implementation (not the interface) file as a way of emulating private methods if you want to "hide" them from users of your class.

Note, although you will no longer be advertising the methods to clients of your class, they will still be able to use them if they use the correct selectors. Additionally, they can always use something like classdump to regenerate the full interface to your class so your methods will never truly be hidden.

See this question for further examples of creating "private" methods under objective-c.

3
  • but then I'll have the "hide" the h file containing the category Commented Jan 20, 2010 at 16:00
  • 2
    @Guy: no, you can implement the category fully within the implementation file. There is nothing to say an @interface section must be in a .h file.
    – jkp
    Commented Jan 20, 2010 at 16:00
  • 1
    @Guy JKP is right, you put it at the top of the .m, it's fairly standard practice. Remember: there is never anything private in objective-c, only invisible or unknown
    – slf
    Commented Jan 20, 2010 at 16:03
-1

You can create a private static function

@implementation Car 

static createBlueCar () {
  ....
}

+(Car*) createCar:(int) color{
   if (color==1) {
     return createBlueCar();
   } ...
}

@end

but no, you cannot create a true private member. (You can invoke some conventions e.g. +(Car*)private_createCar in a private category to discourage its use.)

Not the answer you're looking for? Browse other questions tagged or ask your own question.