Projects

Now that we have a pretty good understanding of Objective-C, let's discuss what Objective-C code looks like in a project. Unlike the Swift code, Objective-C is written in two different types of files. One of the types is called a header file and ends in the extension h. The other type is called an implementation file and ends in the extension m.

Before we can really discuss what the difference is between the two, we first have to discuss code exposure. In Swift, all the code you write is accessible to all other code in your project. This is not true with Objective-C. In Objective-C, you must explicitly indicate that you want to have access to the code in another file.

Header files

The header files are the types of files that can be included by other files. This means that header files should only contain the interfaces of types. In fact, this is why the separation exists between class interfaces and implementations. Any file can import a header file and that essentially inserts all the code of one file into the file that is importing it:

#import <Foundation/Foundation.h>
#import "Car.h"

@interface SteeringWheel : NSObject
@property (weak) Car *car;
@end

This allows us to separate each class into its own file just as we like to do in Swift. The danger is that we must only put code that can be safely imported into headers. If you try to put implementations in a header, you will end up with duplicate implementations for every time you import the header.

In the preceding example, we actually imported one header file into another. This means that if a different file now includes this header file, it will essentially be importing both header files.

You will also notice that there are two different ways to import a file. We import foundation with angled brackets and imported our car header with quotes. Angled brackets are used for importing header files from frameworks, while quotes are used for importing header files within the same framework or application.

A lot of the time it isn't actually necessary for one header file to include another because all it needs to know about is the existence of the class. If it doesn't need to know any actual details about the class, it can simply indicate that the class exists using the @class keyword:

@class Car;

@interface SteeringWheel : NSObject
@property (weak) Car *car;
@end

Now, the compiler will not complain that it doesn't know what Car is. However, you will most likely still need to import the car header in the implementation file because you will probably be interacting with some part of that class.

Implementation files

As you might have guessed, implementation files are generally for the implementation of your types. These files are not imported into others; they simply fulfill the promises of what the interface files have defined. This means that header and implementation files generally exist in pairs. If you are defining a steering wheel class, you will most likely create a SteeringWheel.h header and a SteeringWheel.m implementation file. Any other code that needs to interact with the details of the steering wheel class will import the header and at compile time, the compiler will make all of the implementations available to the running program.

Implementation files are also a great place to hide private code, because they cannot be imported by other code. Since the code is not visible anywhere else, it is unlikely to be interacted with. This means that people will sometimes add class interfaces to implementation files if their use is localized to just that file. It is also very common to add what is called an anonymous category to an implementation file:

@interface SteeringWheel ()
@property NSString *somePrivateProperty;
- (void)somePrivateMethod;
@end

This is considered anonymous because the category was not actually given a name. This means there is no way to pair an implementation directly with that category. Instead, the implementation should be defined within the normal implementation of the class. This provides a great way to define any private properties and methods at the top of an implementation file. You don't technically need to define any private methods because as long as they are implemented in the same file, they can be interacted with. However, it is often nice to have a concise list of the available properties and methods at the top of the file.

This brings up another point, that only methods that you intend to use from outside files should be declared in the header. You should always consider a header to be the public interface of your class and it should be as minimal as possible. It is always written from the perspective of outside files. This is the way that Objective-C implements access control. It isn't formally built into the language but the compiler will warn you if you try to interact with code that has not been imported. It is actually still possible to interact with these private interfaces, especially if you duplicate the interface declaration somewhere else, but it is considered best practice to not do that and Apple will actually reject your apps during review if you try to interact with private parts of their API.

Organization

Other than the obvious difference, the Objective-C projects will have two different types of files. They are organized in the exact same way as Swift files. It is still considered to be a good practice to create folders to group related files together. Most of the time you will want to keep header file and implementation file pairs together, as people will be switching between the two types of files a lot. However, people can also use the keyboard shortcuts Control/Command up arrow or Control/Command down arrow to quickly swap between a header file and its implementation file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset