Using Xcode to Create DGCar Class Files

Xcode is helpful in setting up the skeletal structure of your class files, including the inheritance tree. Now is the time to follow along and create the DGCar class files (and fill them in as the chapter progresses).

Begin by selecting the Classes folder in the Files and Groups panel in the Workbench project window. Selecting this folder as a starting point causes Xcode to insert the files you’re about to create within the Class group. To see the next menu, you have two options:

  • Click to select the Classes folder and pull down the Action menu (the one with the gear icon).

  • Use your choice of secondary click (e.g., Ctrl-click, right-click with a two-button mouse, or two-finger-click with a trackpad) on the Classes folder to reveal the context-sensitive menu.

Choose Add to view the choices of new items you can create. Select New File, as shown in Figure 4-5.

The Add submenu

Figure 4-5. The Add submenu

A New File window opens, shown in Figure 4-6. For the simple class being created here, choose Cocoa Touch Class in the left column, then Objective-C class in the top right group. Next, make sure you specify that this will be a subclass of NSObject. This will cause Xcode to fill in as many pieces as it can into the skeleton files, including the superclass name. Click the Next button.

Choices in the New File dialog window

Figure 4-6. Choices in the New File dialog window

The final step in the creation of the set of partially prewired class files is to name the class, shown in Figure 4-7. It is here where you assign a name to the class. The default file name includes the correct .m extension. The name you enter into the top field becomes not only the name of the two class files, but also the name of the class, which Xcode inserts into the class file templates. Xcode fills in everything else in this dialog box, but be sure to enable the checkbox next to the instruction to also create the .h header file for the class. Then click the Finish button.

Saving the new class files

Figure 4-7. Saving the new class files

Et voilà, your two class files are now created and inserted into the Class group, as shown in Figure 4-8. The new header file (below the comments) consists of the following code:

#import <Foundation/Foundation.h>


@interface DGCar : NSObject {

}

@end
The two class files are created and added to the Classes group

Figure 4-8. The two class files are created and added to the Classes group

Editing the @interface Section

Notice that the @interface directive is balanced by an @end directive, which is always at the end of the header file. In between are two sections for your code. The sections are labeled with placeholders in the following code fragment:

#import <Foundation/Foundation.h>


@interface DGCar : NSObject {

    // instance variable declarations here

}

// method declarations here

@end

These two sections are for declarations—almost a table of contents for the variable and method names to be assigned values and defined in detail within the companion implementation file.

For purposes of this demonstration, the DGCar class is designed to be parallel to the JavaScript Car object described earlier in this chapter. The JavaScript object has three properties and a method; the Objective-C version has three instance variables (also called ivars, pronounced EYE-varz) and two method definitions, as follows:

@interface DGCar : NSObject {

    NSString *make;
    NSString *model;
    NSString *year;

}

- (DGCar *)initWithCarMake:(NSString *)inputMake
                     model:(NSString *)inputModel
                     year:(NSString *)inputYear;
- (NSString *)getFormattedListing;

@end

You can probably recognize that the three JavaScript properties and three Objective-C instance variables serve similar purposes: when an instance of the object is created, that instance is designed to hold three values. Importantly, each instance can hold entirely different values without interfering with another—the essence of the object-oriented programming term, encapsulation.

There are, however, some important differences between the two environments. First, you’ll notice that the Objective-C declarations define each variable as belonging to the NSString class. That is to say, each variable (when eventually initialized) will itself be an instance of the NSString class. Unlike JavaScript, when you define an Objective-C variable as a particular type of data, the data must be of that type and cannot change over the life of that variable. You’ll learn more about data typing in Chapter 6.

An asterisk symbol indicates that the variable is what is known as a pointer to a place in memory where the object containing the value lives. The pointer notation appears with a variable when the variable is being declared, as happens in the header file. Chapter 6 has more information about pointers in Objective-C and how to use them.

Of the two methods defined in the DGCar class header file, the second one, getFormattedListing, parallels the like-named method in the JavaScript version. The leading hyphen tells the compiler that the method is an instance method. A method declaration ends with a semicolon.

In Objective-C, all method declarations must specify the type of data returned when the method finishes running. The data type is placed inside parentheses ahead of the method name. The getFormattedListing method returns a value that is of class NSString (more explicitly, a pointer to an NSString object instance). As you’ll learn later, not all methods return a value (just as not all JavaScript methods or functions return values). In those cases, place the keyword void in the parentheses where the data type goes.

Look now at the other method. Based on its name, it certainly appears to have something to do with initialization. The original JavaScript object constructor function accepts three arguments whose values are assigned to object properties at the same time an instance of the object is created. That same operation takes place in the Objective-C initialization method for this class. In Objective-C syntax, you can construct a method definition to accept arguments. Each argument must have its data type declared (again, covered in more detail in Chapter 6) and the name of a variable to which the value is assigned when the method is called (just like the parameter variables in the JavaScript constructor function’s parentheses). The first argument comes after the method name, separated from it by a colon. Subsequent arguments (if any) have individual, explicit labels, which must have a space or other whitespace character (such as a carriage return) between the end of the previous argument’s parameter variable and the start of the label. Thus, the second argument of the initialization method is named model and its value must be of type NSString. The way you refer to a method when writing or speaking about it is to include all of the argument labels and colons (if any). Therefore, the initialization method is technically referred to as:

initWithCarMake:model:year:

One reason the argument labels are so important is that, unlike in JavaScript, you can reuse a method’s name to define a completely different method with a different set of arguments. Therefore, in this same DGCar class, you could define an additional method as the following and there would be no confusion:

initWithCarMake:model:year:listPrice:

The number of arguments and their labels in a statement that calls the method dictate the precise method being called.

Message Passing

While I’m on the subject of calling methods, Objective-C triggers the execution of methods based on a model that is different from what you use in JavaScript. Because each Objective-C object instance is conceptually a separate entity, the way objects communicate with each other is to send messages to each other. A message may have the feel of invoking an object’s method, but there are important differences. For instance, if an object doesn’t understand a message, the message is ignored and the object simply returns nil to the sender. Therefore, get in the habit of using the “message” terminology, such as, “Object A sends the myMethodWithArgument1:andArgument2: message to Object B.”

One advantage of the argument labels in method definitions is that it’s much easier to understand what the values being passed mean. In the JavaScript version, you just pass three strings and hope you have them in the desired order as needed by the order of the parameter variables in the constructor function. In Objective-C, however, the labels guide you to precisely how you should use each value. Importantly, the order of the labels must be the same in the method definition and the statement sending the message to that method. Just because they have labels doesn’t mean you can mix up the order at will.

Speaking of labels, don’t be afraid to be verbose in devising label names that really define what they’re for. In fact, that goes for everything in Objective-C for which you need to assign a name. In JavaScript and web coding, you are very mindful that each character you apply to a variable or method name means a character that must make the journey from server to browser, occupying Internet bandwidth. But in the compiled Objective-C world, the compiler reduces those long names to very compact tokens. Long names in Objective-C contribute to the readability of your code (but you should not rely on them as replacements for good commenting).

Editing the @implementation Section

The implementation file, which holds the @implementation section, is where you write the code that executes when an instance of the class is created and thereafter. Look first at the empty DGCar.m file that Xcode generated for you (omitting the top comments section):

#import "DGCar.h"


@implementation DGCar

@end

Xcode automatically fills in two items. The first is the #import preprocessor directive. Whenever a class definition is divided into separate header and implementation files, the implementation file must instruct the preprocessor to import the companion header file. Notice that for importing class header files that are not frameworks, the header file name is in quotes rather than the angle brackets used for importing frameworks (as was done in the header file). The difference between quotes and brackets is that quotes instruct the preprocessor to start looking for the file within the same directory as the current implementation file. Since framework files are stored elsewhere, the angle brackets tell the preprocessor to skip the current directory.

If the @interface and @implementation sections were in the same file, both sections would already be together, meaning the @implementation section could see all the declarations in the @interface section and no importing would be necessary. Despite the apparent simplicity of having both sections in one file (especially if you need to make changes to method names or arguments during development), don’t fight Xcode’s will in generating header/implementation file pairs for your classes.

The blank @implementation section Xcode generates is even simpler than the blank @interface section shown earlier. There are no curly-braced subsections to deal with. Almost all of your code goes between the @implementation and @end compiler directives.

Adding the getFormattedListing method

Now we’ll inspect the details of a method definition and see how the Objective-C form compares to what you know about JavaScript methods. The two versions described in this chapter share the same basic name, getFormattedListing. The Objective-C version is as follows:

- (NSString *)getFormattedListing {
    NSString *result = @"";

    result = [NSString stringWithFormat:@"[%@] %@ %@", year, make, model];

    return result;
}

Many things about this definition will look familiar to you. Compare the two language formats for method definition structure:

JavaScript:

function methodName() {
    // Statements
}

Objective-C:

- (returnType)methodName {
    // Statements
}

An Objective-C instance method definition begins with a hyphen symbol, followed by the return value type in parentheses and the method name. A block of statements to execute when the object receives a message matching the method name is contained inside a set of curly braces. Different programmers (in JavaScript, too) adhere to different styles of curly brace placement for blocks. Some place the left curly brace on the same line as the method name; others place the left brace at the start of the next line. Use the style you prefer.

The job of the getFormattedListing method is to read the values of the instance variables, insert them into a string, and return the entire string as an NSString type. It begins by creating an empty NSString object named result. The second statement sends a message to the NSString class (not an instance) to invoke one of its class methods to plug the ivar values into placeholders within a string (more about formats in a moment). This NSString message returns a new NSString object, which is assigned to result, the value returned at the end.

Message syntax

You can see in the second statement of getFormattedListing what an Objective-C message looks like (the expression to the right of the assignment (=) operator). Forget everything you know about JavaScript method-calling syntax, and get ready for the Objective-C way of doing things. Sending a message requires at least two pieces of information:

  • A reference to the intended recipient object, i.e., the message’s receiver

  • The name of method to be called (plus any arguments and passed values)

These pieces are embedded inside square brackets in the following format:

[receiver method]

To send a message containing a single argument, the syntax format is as follows:

[receiver method:argument]

Each additional argument consists of a label and a value, separated by a colon, as in the following format:

[receiver method:argument labelA:argumentA labelB:argumentB]

You can add one or more spaces around the square brackets if it helps with your code readability. I predict that until you get used to the square bracket notation, you will inevitably start writing messages without them because of your experience with JavaScript syntax. Additionally, every message includes a receiver, even if the message you’re sending aims to invoke a method in the current class definition. In those cases (as you will see many times later in the book), the receiver is—you guessed it—self, as in the following message, which calls a loadNewData method defined elsewhere in the current class (and which does not return a value):

[self loadNewData];

Adding the initWithCarMake:model:year: method

Every Objective-C object derived from NSObject inherits from that base object the init method. That method is used as part of the process to generate an instance of the object (in addition to memory allocation, which you’ll learn about in Chapter 6). If your custom class does nothing special when it creates an instance of itself, there is no need for you to define an init method in your class: the object will receive the init message and automatically use the init method defined for its superclass, NSObject. That’s how inheritance and message passing work.

In the case of the DGCar class defined here, its code follows the model in the JavaScript version, in that whenever an object instance is created, that instance is handed three string values to be assigned to instance variables. To accommodate that, the DGCar class defines a customized initialization method, named initWithCarMake:model:year:. The definition of that method follows:

- (DGCar *)initWithCarMake:(NSString *)inputMake
                     model:(NSString *)inputModel
                      year:(NSString *)inputYear {
    // If initialization of the superclass succeeds,
    // then assign instance variables
    if (self = [super init]) {
        make = inputMake;
        model = inputModel;
        year = inputYear;
    }
    return self;
}

The method definition signifies with the leading hyphen that it is an instance method. Initialization methods always return a value that is a reference to the object instance. You may have seen this same concept in JavaScript constructor functions that end with a return this statement: the constructor function returns a reference to the instance object just created. Therefore, the initialization method for DGCar returns a reference to the very same object instance being created. The asterisk indicates that the value is a pointer to the object instance in memory (pointers are covered in Chapter 6).

When an Objective-C method accepts arguments, each argument is assigned to a variable—the same way JavaScript function arguments are assigned to parameter variables. The difference in Objective-C is that you must specify the data type for each one. Therefore, the car make must be passed to the DGCar initialization method as an NSString type of object. The same goes for the other two arguments. Just as the method returns a pointer to the object instance, the incoming arguments are assigned to variables that hold pointers to their locations in memory. Thus, the (NSString *) data type designations all have asterisks. If you omit or forget the asterisks, the compiler will complain that the argument is defined with an incorrect data type.

Because the DGCar class has its own initialization method, the first task for that method is to send the “normal” init message to the NSObject superclass. You don’t necessarily need to know everything the method does in the superclass, but it is vital to completing the object’s instantiation. And, just as the DGCar class’s initialization method returns a reference to the instance being created, so does the NSObject’s init method. The DGCar method needs to capture that reference and apply it to itself. The way to do that is to assign the value returned by the NSObject’s init method to a DGCar property that references the instance object being defined by the current class (self):

    self = [super init];

Notice that this action is embedded within an if condition. The code confirms that the root object initialization was successful before continuing with the subclass initialization. If the superclass initialization were to fail, the condition expression would evaluate to nil, causing the nested statements to be skipped. Performing these kinds of success tests is good practice, even if the likelihood of failure approaches zero.

When the superclass initialization succeeds, parameter variables are assigned to the three instance variables that had been declared in the class’s interface. When you write the code in Xcode, the editor color codes instance variables that have been correctly declared (the default is green, but you can change color coding in Preferences). It is vital that the data types of the parameter variables match exactly the data types of the instance variable declarations. Xcode closely checks the consistency of data types as it builds an app. Mistakes will be highlighted before the app ever reaches the simulator.

The last statement of the DGCar initialization method returns a reference to the current instance—self. A return value’s data type must match the data type declared at the start of the method definition. In this case, the self keyword references an instance of the DGCar class being initialized here. The returned value could also be nil, which would occur if the superclass initialization failed. As you’ll see in a moment, the reference to a successfully created instance will be assigned to a variable elsewhere so that the instance can receive further messages.

Get Learning the iOS 4 SDK for JavaScript Programmers 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.