2

I know some C++ and now I will try to learn Objective-C as well. My book mentioned class methods briefly and said that class methods are messages that can be sent to a class, often it is used to create an instance of the class.

Does this mean that class methods are kind of like constructors in C++? In my case, I have a card game with a Deck class (currently in C++). When I create an instance of it, I do this:

Deck deckWithCards(52);  // A deck with 52 cards with values
Deck deckWithoutCards;   // An empty deck

If I was to do the same thing in Objective-C, is it considered good "style" to do it like this:

Deck *deckWithCards = [Deck newDeck:52]; // A deck with 52 cards with values
Deck *deckWithoutCards = [Deck newDeck]; // An empty deck

Have I understood class methods correctly? Are there other uses for class methods?

  • 1
    I know zip about Objective-C, but judging from the name "class method" and how it's used in most other langauges, it would correspond to a `static` member function in C++. – Angew is no longer proud of SO Feb 14 '14 at 11:39
  • ObjC class methods, and C++ static member functions, are sometimes used to create "factory" functions, which is what you've described. A factory function is a function whose purpose is to provide you an object... it's the object factory. When a constructor is involved, the factory function calls it (perhaps based on input you've provided). In C++, directly calling a constructor resembles the pattern of using a factory function but since the constructor does not allocate the object, it's not a factory. – mah Feb 14 '14 at 11:52
  • You can do it this way, but please, do **not** do it! Factory methods are nice as shortcuts but generally you should use the `[[object alloc] init]` syntax. If you want to do it shortened like that, you can use the class method `new` which is already provided for you. Don't reinvent the wheel. – SevenBits Feb 14 '14 at 12:34

4 Answers4

2

Class methods are what's called "static member function" in C++.

The "named constructor" idiom of Objective-C is sometimes used in C++ as well:

class Deck
{
public:
    static Deck* newDeck(int cards = 0);
    // ...
};

// ...

Deck* deckWithCards = Deck::newDeck(52);
Deck* deckWithoutCards = Deck::newDeck();

But in the presence of overloadable constructors it's not as useful.
It also doesn't go very well together with RAII.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
2

Does this mean that class methods are kind of like constructors in C++?

They are more like static member functions. For example, you may specify the return type of a class method. ObjC's class methods however, use dynamic dispatch.

The initializer is more like a constructor.

If I was to do the same thing in Objective-C, is it considered good "style" to do it like this: …

Really, you should decompose what happens here. There is nothing wrong with using a convenience constructor where it makes sense. Typically, you would not bother to declare a convenience constructor, and instead customize initialization using your objects' initializers (these are instance methods with the prefix -init…).

Rather than use, +newDeckWithNCards: and +newDeck, you would begin by defining or overriding the designated initializer:

- (instancetype)init;
- (instancetype)initWithNCards:(NSUInteger)pNCards;

In some cases, it can be convenient to provide the convenience constructor, and sometimes you will prefer the class method or factory when implementing a class cluster (which many people never do).

In most cases, the initializer is adequate, but it's certainly not bad to use convenience constructors in some cases.

Class methods can be used for much more. Again, think of them like static member functions which also have dynamic dispatch (so an NSString method may execute a different implementation than NSMutableString within its class method via override, and this is determined at runtime).

justin
  • 104,054
  • 14
  • 179
  • 226
1

Class methods are most similar to static methods in C++. However they are not the same. In C++ classes don't exist at runtime. Classes in Objective-C are real objects which you can call methods on (send a message to, in Objective-C lingo). So in Objective-C you can do stuff like this:

Class classObj = [NSString class];
NSString *instanceObj = [classObj stringWithFormat:@"Hi I am %d years old", 36];

Which is similar to doing:

NSString *instanceObj = [NSString stringWithFormat:@"Hi I am %d years old", 36];

You might wonder what the purpose of that is, well it gives you the Factory pattern for free. You can e.g. use it to load a class from a plugin and the call class methods on your loaded class without knowing which class it is.

With respect to your example. In Objective-C one usually separates allocation from initialization, so:

Deck *deckWithCards = [Deck newDeck:52];

Is not recommended. Instead you should write it as:

Deck *deckWithCards = [[Deck alloc] initWithNoCards:52];

Back to your original question are class methods the same as constructors. As I have shown they are not really, although I can understand why you make the comparison, because they have some overlapping usage.

But there is really nothing like constructors in Objective-C. Constructors in C++ and Java are part of the language and have a very specific purpose. You can't create objects without invoking a constructor in C++ and Java. In Objective-C this is not hardwired into the language. It is all about convention. alloc and init are just conventions. Likewise you can use class methods to do anything. They don't have to create any objects.

If you want to get more into detail about how this works I recommend Mike Ash's article about how you can implement NSObject.

Erik Engheim
  • 8,182
  • 4
  • 36
  • 51
  • The article you linked to is good but perhaps a bit too complex for someone just trying to understand static methods. – SevenBits Feb 14 '14 at 13:04
  • @SevenBits yes it is potentially way too much, but I think it depends on the person. For a quick answer it is not helpful. But for somebody who really wants to understand why static methods are not the same as class methods in the context of object creation it could be very useful. – Erik Engheim Feb 14 '14 at 13:46
-1

No, it is not good practice. You can do it this way, but please, do not do it! Factory methods are nice as shortcuts but generally you should use the [[class alloc] init] syntax. If you want to do it shortened like that, you can use the class method new which is already provided for you. Don't reinvent the wheel.

I have seen APIs and programmers do things the way you just did and I know instantly that they come from languages like C++ where things like this are common and I know they're not "native" Objective-C programmers. It's important to remember that C-like languages are incredibly flexible, and just because you can do something doesn't mean that you should.

Now factory methods, like what you are describing, are useful in some circumstances, but definitely not your example. For example, factory methods are used in NSString in places like stringWithFormat: because it would be difficult to do otherwise and a pain in the neck with the default paradigm, but they are the exception, not the rule.

Just my two cents.

SevenBits
  • 2,836
  • 1
  • 20
  • 33
  • How should I do the creation of a Deck in my case? Is it: `Deck *myDeck = [Deck new];` and then `[myDeck setCards:52];`? –  Feb 14 '14 at 17:03
  • Yes, or: `Deck *myDeck = [[Deck alloc] initWithCards:52];` which the best, most Cocoa-like way. – SevenBits Feb 14 '14 at 17:10