The declaration of a class interface begins with the compiler directive @interface and ends with the directive @end. (All Objective-C directives to the compiler begin with “@”.)
@interface ClassName : ItsSuperclass |
{ |
instance variable declarations |
} |
method declarations |
@end |
The first line of the declaration presents the new class name and links it to its superclass. The superclass defines the position of the new class in the inheritance hierarchy, as discussed under “Inheritance.” If the colon and superclass name are omitted, the new class is declared as a root class, a rival to the NSObject class.
Following the first part of the class declaration, braces enclose declarations of instance variables, the data structures that are part of each instance of the class. Here’s a partial list of instance variables that might be declared in the Rectangle class:
float width; |
float height; |
BOOL filled; |
NSColor *fillColor; |
Methods for the class are declared next, after the braces enclosing instance variables and before the end of the class declaration. The names of methods that can be used by class objects, class methods, are preceded by a plus sign:
+ alloc; |
The methods that instances of a class can use, instance methods, are marked with a minus sign:
- (void)display; |
Although it’s not a common practice, you can define a class method and an instance method with the same name. A method can also have the same name as an instance variable. This is more common, especially if the method returns the value in the variable. For example, Circle has a radius method that could match a radius instance variable.
Method return types are declared using the standard C syntax for casting one type to another:
- (float)radius; |
Argument types are declared in the same way:
- (void)setRadius:(float)aRadius; |
If a return or argument type isn’t explicitly declared, it’s assumed to be the default type for methods and messages—an id. The alloc method illustrated earlier returns id.
When there’s more than one argument, the arguments are declared within the method name after the colons. Arguments break the name apart in the declaration, just as in a message. For example:
- (void)setWidth:(float)width height:(float)height; |
Methods that take a variable number of arguments declare them using a comma and ellipsis points, just as a function would:
- makeGroup:group, ...; |
Importing the Interface
Referring to Other Classes
The Role of the Interface
The interface file must be included in any source module that depends on the class interface—that includes any module that creates an instance of the class, sends a message to invoke a method declared for the class, or mentions an instance variable declared in the class. The interface is usually included with the #import directive:
#import "Rectangle.h" |
This directive is identical to #include, except that it makes sure that the same file is never included more than once. It’s therefore preferred and is used in place of #include in code examples throughout Objective-C–based documentation.
To reflect the fact that a class definition builds on the definitions of inherited classes, an interface file begins by importing the interface for its superclass:
#import "ItsSuperclass.h" |
@interface ClassName : ItsSuperclass |
{ |
instance variable declarations |
} |
method declarations |
@end |
This convention means that every interface file includes, indirectly, the interface files for all inherited classes. When a source module imports a class interface, it gets interfaces for the entire inheritance hierarchy that the class is built upon.
Note that if there is a precomp—a precompiled header—that supports the superclass, you may prefer to import the precomp instead.
An interface file declares a class and, by importing its superclass, implicitly contains declarations for all inherited classes, from NSObject on down through its superclass. If the interface mentions classes not in this hierarchy, it must import them explicitly or declare them with the @class directive:
@class Rectangle, Circle; |
This directive simply informs the compiler that “Rectangle” and “Circle” are class names. It doesn’t import their interface files.
An interface file mentions class names when it statically types instance variables, return values, and arguments. For example, this declaration
- (void)setPrimaryColor:(NSColor *)aColor; |
mentions the NSColor class.
Since declarations like this simply use the class name as a type and don’t depend on any details of the class interface (its methods and instance variables), the @class directive gives the compiler sufficient forewarning of what to expect. However, where the interface to a class is actually used (instances created, messages sent), the class interface must be imported. Typically, an interface file uses @class to declare classes, and the corresponding implementation file imports their interfaces (since it will need to create instances of those classes or send them messages).
The @class directive minimizes the amount of code seen by the compiler and linker, and is therefore the simplest way to give a forward declaration of a class name. Being simple, it avoids potential problems that may come with importing files that import still other files. For example, if one class declares a statically typed instance variable of another class, and their two interface files import each other, neither class may compile correctly.
The purpose of the interface file is to declare the new class to other source modules (and to other programmers). It contains all the information they need to work with the class (programmers might also appreciate a little documentation).
The interface file tells users how the class is connected into the inheritance hierarchy and what other classes—inherited or simply referred to somewhere in the class—are needed.
The interface file also lets the compiler know what instance variables an object contains, and tells programmers what variables subclasses inherit. Although instance variables are most naturally viewed as a matter of the implementation of a class rather than its interface, they must nevertheless be declared in the interface file. This is because the compiler must be aware of the structure of an object where it’s used, not just where it’s defined. As a programmer, however, you can generally ignore the instance variables of the classes you use, except when defining a subclass.
Finally, through its list of method declarations, the interface file lets other modules know what messages can be sent to the class object and instances of the class. Every method that can be used outside the class definition is declared in the interface file; methods that are internal to the class implementation can be omitted.
Last updated: 2008-02-05