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 “Application” under Mac OS X from the left side, then choose “Command Line Tool” from the top right, and make sure the “Type” is set to Foundation. Click Choose, and save it as “FractionDemo” anywhere you choose. In the File List, load FractionDemo.m, and enter the following code:

  1. #import "Fraction.h"
  2. #import
  3.  
  4. int main (int argc, const char * argv[]) {
  5.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  6.  
  7.     Fraction *myFraction = [[Fraction alloc] init];
  8.  
  9.     // Set myFraction to value of 2/5
  10.     [myFraction setNumerator: 2];
  11.     [myFraction setDenominator: 5];
  12.  
  13.     // Display the value of myFraction
  14.     NSLog(@"myFraction has a value of: ");
  15.     [myFraction display];
  16.  
  17.     [myFraction release];
  18.     [pool drain];
  19.     return 0;
  20. }

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). From the left, choose Cocoa Class under Mac OS X, select Objective-C class from the top left, and make it a Subclass of NSObject. Click Next, and set the following parameters:

  1. Set the File Name to be “Fraction.m”. Note that the “.m” part is automatically added; just type “Fraction”, without the quotes, making sure that the “F” is capitalized. By convention, class names are capitalized.
  2. Make sure that ‘Also create “Fraction.h”‘ is selected.
  3. Leave the default settings for the other fields. Add to Project should display “FractionDemo,” the name of your project, and in your Targets window, the checkbox to the left of the “FractionDemo” entry should be selected.

Click “Finish”. In your File List, you will see two new files: “Fraction.h” and “Fraction.m.” Select Fraction.h, and enter the following code:

  1. #import <Foundation/Foundation.h>
  2.  
  3. @interface Fraction : NSObject {
  4.     NSInteger numerator;
  5.     NSInteger denominator;
  6. }
  7. - (void)setNumerator:(NSInteger)value;
  8. - (void)setDenominator:(NSInteger)value;
  9. - (void)display;
  10.  
  11. @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.

In Fraction.m, enter the following code:

  1. #import "Fraction.h"
  2.  
  3. @implementation Fraction
  4. - (void)setNumerator:(NSInteger)value {
  5.     numerator = value;
  6. }
  7.  
  8. - (void)setDenominator:(NSInteger)value {
  9.     denominator = value;
  10. }
  11.  
  12. - (void)display {
  13.     NSString *numeratorString = [[NSString alloc] initWithFormat:@"%d", numerator];
  14.     NSString *denominatorString = [[NSString alloc] initWithFormat:@"%d", denominator];
  15.     NSLog(@"%@/%@", numeratorString, denominatorString);
  16.     [denominatorString release];
  17.     [numeratorString release];
  18. }
  19.  
  20. @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

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

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:

  1. myFraction has a value of:
  2. 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.

Author: Feifan Zhou