Learn Objective-C, Objects (Part 1): Splitting Classes Into Multiple Files

This is the first in a multi-part series that will talk about the fundamentals of objects. If you’re still keeping track, I suppose these would all fall under Lesson 6: Objects.

In Lesson 3, we began a simple overview to object-oriented programming. Now, we’ve covered the major portions of the basic language- what is “plain C.” There are other topics, such as structs, arrays, and a slew of other rather obscure topics. Some of these are enclosed or remade in the code the Apple provides for free; others will be discussed as necessary. For now, we will start venturing into the exciting world of objects- and they really are exciting.

As part of our calculator, we will allow the calculator to operate on regular values, as well as fractions. For the sake of demonstration, we will begin by creating Fraction objects.

Creating the Test Code

Create a new Xcode project. In the New Project window, choose “Command Line Tool” under macOS. Click Next, and save it as “FractionDemo” anywhere you choose. In the File List, load FractionDemo.m, and enter the following code:

#import "Fraction.h"

int main (int argc, const char *argv[]) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Fraction *myFraction = [[Fraction alloc] init];

    // Set myFraction to value of 2/5
    [myFraction setNumerator: 2];
    [myFraction setDenominator: 5];

    // Display the value of myFraction
    NSLog(@"myFraction has a value of: ");
    [myFraction display];

    [myFraction release];
    [pool drain];
    return 0;
}

Here, you can see that in our main code body, we create an object of type Fraction, and call it myFraction. Ignore the asterisk (* for now; it is a sign that you are actually creating a pointer…that’s an advanced topic that will be further explored later). You set myFraction to the value returned from the standard alloc/init method call.

Next, we call the methods setNumerator: and setDenominator: and pass both integer values; these methods will set the appropriate values of the Fraction object we’ve created. We then send another message call for myFraction to display itself (or so we assume, based on the method name—make sure to write descriptive method names). Then we release our object—don’t worry about the memory management for now.

Now, we will create the actual Fraction object itself.

Creating the Fraction Class

In Xcode, Go to File > New File (⌘N). Under the macOS tab, select “Header File”. Click Next. Enter “Fraction” for the header name. It should appear as “Fraction.h”. Click Create. Select the “Fraction.h” file in Xcode, and enter the following code:

#import <Foundation/Foundation.h>

@interface Fraction : NSObject {
    NSInteger numerator;
    NSInteger denominator;
}
- (void)setNumerator:(NSInteger)value;
- (void)setDenominator:(NSInteger)value;
- (void)display;

@end

Here we define two instance variables, called “numerator” and “denominator”. They are defined as type NSInteger; this is identical to the standard int type; there’s really no difference. My personal preference is NSInteger.

Next, we define the methods that we call in the main() method. There should not be anything new here, if you’ve read through Lesson 3.

Create “Fraction.m” by creating another new file. Follow the steps above, except create an “Objective-C File” instead of a “Header File”. Enter “Fraction” in the text field, after selecting Next. Do not touch either of the drop down menus. Click Create, and enter the code below:

#import "Fraction.h"

@implementation Fraction
- (void)setNumerator:(NSInteger)value {
    numerator = value;
}

- (void)setDenominator:(NSInteger)value {
    denominator = value;
}

- (void)display {
    NSString *numeratorString = [[NSString alloc] initWithFormat:@"%d", numerator];
    NSString *denominatorString = [[NSString alloc] initWithFormat:@"%d", denominator];
    NSLog(@"%@/%@", numeratorString, denominatorString);
    [denominatorString release];
    [numeratorString release];
}

@end

Chewing through this code, the first two methods should not present anything new. The last method does warrant some discussion, however.

If you refer back to Lesson 3, you’ll notice that we defined the display method (we called it showResults there) as

- (void)showResults {
    NSLog(@"This is a fraction with a value of %d/%d", numerator, denominator);
}

Our display method shows a different way to do this. First, we highlight NSString’s initWithFormat: method, which works like NSLog() does, except that instead of outputting, it is saved as a string. In the actual NSLog(), we use the %@ format specifier, which takes an NSString as an argument. Finally, we have to release the NSStrings that we’ve created… again, don’t worry about the memory management at the moment.

If we Build and Run now, we get the following output:

myFraction has a value of:
2/5

This is exactly what we’re looking for.

You’ll notice that we haven’t really done anything new since Lesson 3. In fact, that is true, except that we have created a Fraction class in separate files. Looking back over the code entries, the bold lines show where the dependencies lie- in a class’s .m file, it #imports the correspond .h (known as the “header”) file. In any file that uses the class you’ve created, you also need to import the header. Here, you’ve made it easier to maintain a larger project; as we add more classes, you won’t be working with one gigantic file.

This post is part of the Learn Objective-C in 24 Days course.


Previous Lesson Next Lesson