This is a very petty point, but I believe there’s a right answer, and since it’s come up before I’m going to take the time to justify the best choice.
Forward Declare Classes on One Line, Not Many Lines
Right:
@class Foo, Bar, Baz...;
This is the style that Apple’s headers generally follow, look at NSDocument.h
for example.
Wrong:
@class Foo;
@class Bar;
@class Baz;
...
Programming languages are to be read by people first, and interpreted by computers second. I really do hope anyone in software engineering can take that as an axiom!
Therefore, always favor brevity above all else with statements that are only for the compiler. They are by far the least important part of the code base. Keeping them terse minimizes distractions from code that can and should be read.
Naturally, it’s very hard to find a statement that’s only for the compiler. I can only think of one such statement in Objective-C, forward declarations of an object with @class
.
What Does @class
Do?
@class Foo;
tells the compiler that Foo
is an Objective-C class, so that it knows how much space to reserve in memory for things of type Foo
. It does not tell the compiler what methods and ivars a Foo
has, to do that you need to #import "Foo.h"
(or have an @interface Foo...
in your .m file.)
@class Foo; |
#import "Foo.h" |
---|---|
Foo is a black box. You can only use it as an argument. |
You can also send messages to Foo . |
What is @class
Good For?
Since #import "Foo.h"
does everything @class Foo;
does and more, why would you ever use @class
? The short answer is less time wasted compiling.
Lets say you have a Controller
class, and it has an ivar that’s a Foo
. To get it to compile, you put #import "Foo.h"
inside Controller.h
. So far so good. The problem comes when Foo.h
is changed. Now any file that has #import "Foo.h"
in it must be recompiled. So Controller.h
has to be recompiled. So any file that has #import "Controller.h"
in it must also be recompiled, and so on. Many objects that don’t use Foo
objects, but do talk to the Controller
(or to something that talks to something that talks to the Controller
!) have to be rebuilt as well. It’s likely that the entire project would end up being rebuilt. With even a moderately sized project, that means a lot of needless compile time!
One solution is to put a forward-declaration, @class Foo;
, in Controller.h
, and #import "Foo.h"
in Controller.m
, and the few files that actually do something to Foo
objects. @class Foo;
gives the compiler just enough information to build an object with a Foo*
ivar, because it knows how much space that ivar will need in memory. And since only objects that need to talk to Foo
objects directly have any dependency on Foo.h
, changes to Foo
can be tested quickly. The first time I tried this solution in one of my projects, compile times dropped from minutes to seconds.
Readers Need Less @class
Forward declarations add value to the development process, as does anything that saves programmers time. But @class
tells a human reader nothing. Which is why I say you should use them in your code, but minimize the space they take up, by putting them all on one line.
@class Foo;
tells a reader that “Foo
is black-box that is a class.” That adds no useful information.
If the reader does not care about what a Foo
is (they are treating it as a black box), then knowing that Foo
is a class is useless information. Foo
could be a struct
, or a bit-field, or a function pointer, or anything else and they still would not need to know to understand the code.
Conversely, if they need to know what a Foo
is to understand the code, then they need to know more then “it is a class”. They need to see Foo.h
or documentation — @class
just isn’t enough.
Exceptions
I want to again emphasize that this isn’t a big deal. I strongly feel that putting all forward declarations on one line is the right answer, but doing it wrong won’t perceptibly matter in the end.
So I don’t think there’s any reason to address exceptions to the rule. Do what you gotta do.
Best Practices
Use @class
to speed up compile-times as much as you can, but use the keyword @class
as little as possible, since it is for the compiler, not the person reading the code.