Header File and Implementation File

It’s perfectly possible for the interface and implementation of a class to appear in the same file, or for multiple classes to be defined in a single file, but that isn’t the usual convention. The usual convention is one class, two files: one file containing the interface section, the other file containing the implementation section. For example, let’s suppose you are defining a class MyClass. Then you have two files, MyClass.h and MyClass.m. (The file naming is not magical or necessary; it’s just part of the convention. The file extensions are pretty much necessary, though, because the build process and Xcode itself rely on them.) The interface section goes into MyClass.h, which is called the header file. The implementation section goes into MyClass.m, which is called the implementation file. The separation into two files is not inconvenient, because Xcode, expecting you to follow this convention, makes it easy to jump from editing a .h file to the corresponding .m file and vice versa (Navigate → Jump to Next Counterpart). Finally, the implementation file imports the header file (see Chapter 1 on the #import directive); this effectively unites the full class definition, making the definition legal even though it is split between two files.

With this arrangement in place, further imports become easy to configure. The header file imports the basic header file for the entire Cocoa framework; in the case of an iOS program, that’s UIKit.h (again, see Chapter 1). There is no need for the implementation file to import UIKit.h, because the header file imports it, and the implementation file imports the header file. If a class needs to know about another class that isn’t already imported in this way, its implementation file imports that class’s header file. Example 4-1 summarizes this conventional schema.

Example 4-1. Conventional schema for defining a class
// MyClass.h:

#import <UIKit/UIKit.h>

@interface MyClass : NSObject
- (NSString*) sayGoodnightGracie;
@end

// MyClass.m:

#import "MyClass.h"
#import "OtherClass.h"

@implementation MyClass {
    // instance variable declarations go here
}
- (NSString*) sayGoodnightGracie {
    return @"Good night, Gracie!";
}
@end

The result of this arrangement is that everything has the right visibility. No file ever imports an implementation file; that way, what’s inside a class’s implementation file is private to that class. If something about a class needs to be public, such as a method that you want other classes to be able to call, it is declared in the header file, and other classes import that header file in their implementation files (as I do with OtherClass.h in Example 4-1); this keeps the chain of imports clear and simple.

A header file is also an appropriate place to define constants. In Chapter 1, for example, I talked about the problem of mistyping the name of a notification or dictionary key, which is a literal NSString, and how you could solve this problem by defining a name for such a string:

#define MYKEY @"mykey"

The question then arises of where to put that definition. If only one class needs to know about it, the definition can go near the start of its implementation file (it doesn’t need to be inside the implementation section). But if multiple classes need to know about this name, then a header file is an appropriate location; every implementation file that imports this header file will acquire the definition, and you can use the name MYKEY in that implementation file.

Note

The ultimate header file in an Xcode project is the .pch file. The suffix .pch stands for “precompiled header”, and your project has exactly one such file, which is implicitly imported by all .h files. It isn’t common to edit the .pch file, but sometimes it’s the most convenient place to define a constant, or even to import a class interface section, that needs to be visible to pretty much every class in your program. I’ll talk more about the .pch file in Chapter 6.

A slight problem arises when a header file needs to mention one of your other classes. Suppose, for example, that MyClass has a public method that takes or returns an instance of MyOtherClass. So MyClass.h needs to speak of MyOtherClass*. But MyClass.h does not import MyOtherClass.h, so MyClass.h doesn’t know about MyOtherClass, and the compiler will complain. To silence the compiler without violating the arrangement of imports (by importing MyOtherClass.h in the header file MyClass.h), use the @class directive. The word @class is followed by a comma-separated list of class names, ending with a semicolon. So MyClass.h might start out like this:

#import <UIKit/UIKit.h>
@class MyOtherClass;

Then the interface section would follow, as before. The @class directive simply tells the compiler, “Don’t worry, MyOtherClass really is the name of a class.” That’s all the compiler needs to know in order to permit the mention of the type MyOtherClass* in the header file.

If, on the other hand, MyClass is to be a subclass of some other class, then MyClass’s header file must import that superclass’s header file (or some other header file that imports that superclass’s header file); otherwise, it would be unable to speak of that superclass. For instance, in Example 4-1, MyClass.h imports UIKit.h; thus it knows about NSObject, so that MyClass can declare NSObject as its superclass.

The Global Namespace

When defining classes, choose your class names wisely to prevent name collisions. Objective-C has no namespaces; there’s a single vast namespace containing all names. You don’t want your own class name (or, for that matter, any other top-level constant name) to match a name defined in Cocoa. Instead of namespaces, there’s a convention: each Cocoa framework prefixes its names with a particular pair of capital letters (NSString and NSArray, CGFloat and CGRect, and so on). Apple suggests that you use a prefix of your own as well; in fact, when you create a new project in Xcode, you’re offered an opportunity to specify a prefix, which will appear before the automatically created class names. Don’t use any of Apple’s prefixes. Nothing limits your prefix to two letters, or requires that both letters be uppercase. In fact, because all of Apple’s own prefixes are two uppercase letters, “My” as a prefix is safe.

Get Programming iOS 6, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.