Intro to Object-Oriented Design: Part 1/2

This tutorial series will teach you the basics of object-oriented design. In this first part: Inheritance, and the Model-View-Controller pattern. By Ellen Shapiro.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

A Minor Digression: Class Methods vs. Instance Methods

You’ve probably noticed when writing code that some methods have a + and some methods have a in front of them. These indicate whether a method is a Class method or an Instance method.

The simplest way to think of the difference is like a schematic blueprint in the physical world: There’s only one blueprint for something, but using that blueprint, you can make many different copies.

A class method, represented by the + symbol, is an action that can be performed with that blueprint, but without creating a specific copy of the object from that blueprint. For example, NSString has the stringWithFormat: class method to create new string objects.

An instance method, represented by the symbol, requires a specific copy of the object created using that blueprint to perform any action. For example, the NSString instance @"Hello There" has an instance method lowercaseString that would return @"hello there". A class method lowercaseString wouldn’t make any sense since that’s just the blueprint for a string – there’s no actual text to lower case!

Adding Basic Methods to Your Class

Go to Vehicle.h and add the following method declarations to the header file, just below the properties you added earlier, and before @end:

//Basic operation methods
-(NSString *)goForward;
-(NSString *)goBackward;
-(NSString *)stopMoving;
-(NSString *)changeGears:(NSString *)newGearName;
-(NSString *)turn:(NSInteger)degrees;
-(NSString *)makeNoise;

A method declaration in a header file is public – it tells other objects looking at your class, “Here’s what I’m going to be able to do”, but it doesn’t give any details of how it’s done. To do that, open Vehicle.m and add the following implementations, or actual code to execute, for each of these methods:

-(NSString *)goForward
{
    return nil;
}

-(NSString *)goBackward
{
    return nil;
}

-(NSString *)stopMoving
{
    return nil;
}

-(NSString *)turn:(NSInteger)degrees
{
    //Since there are only 360 degrees in a circle, calculate what a single turn would be.
    NSInteger degreesInACircle = 360;
    
    if (degrees > degreesInACircle || degrees < -degreesInACircle) {
        //The % operator returns the remainder after dividing. 
        degrees = degrees % degreesInACircle;
    }
    
    return [NSString stringWithFormat:@"Turn %d degrees.", degrees];
}

-(NSString *)changeGears:(NSString *)newGearName
{
    return [NSString stringWithFormat:@"Put %@ into %@ gear.", self.modelName, newGearName];
}

-(NSString *)makeNoise
{
    return nil;
}

Most of this code is just the skeleton of setting up the methods; you'll fill in the implementation details later. The turn: and changeGears: methods have some logging output too, which will help you test that your methods are working before you continue any further in the tutorial.

Open AppDelegate.m, and add an import to the top of the file:

#import "Vehicle.h"

This will allow you to access the Vehicle class from your own code.

Next, replace the implementation of application:didFinishLaunchingWithOptions: with the following:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    Vehicle *vehicle = [[Vehicle alloc] init];
    //Test methods with implementations
    NSLog(@"Vehicle turn: %@", [vehicle turn:700]);
    NSLog(@"Vehicle change gears: %@", [vehicle changeGears:@"Test"]);
    
    //Test methods without implementations
    NSLog(@"Vehicle make noise: %@", [vehicle makeNoise]);
    NSLog(@"Vehicle go forward: %@", [vehicle goForward]);
    NSLog(@"Vehicle go backward: %@", [vehicle goBackward]);
    NSLog(@"Vehicle stop moving: %@", [vehicle stopMoving]);
    
    return YES;
}

Once the vehicle instance is instantiated, you'll call each of the instance methods and log the output to see what they do.

Build and run your app; you’ll see that all implemented strings return proper logs with the appropriate items filled in. But anywhere a property isn’t set or a method returns nil, you’ll see a (null), as follows:

Log output

You'll be using Inheritance to provide more specific implementations of each of these methods.

Inheritance

The basic concept of inheritance is similar to that of genetics: children inherit the characteristics of their parents.

However, it’s a lot more strict than real world genetics in a single-inheritance language like Objective-C. Rather than having two parents from whom you inherit a mix of characteristics, “child” classes, or subclasses, inherit all the characteristics of their “parent” classes, or superclasses.

NSObject, which Vehicle inherits from, is the lowest-level class you can use in Objective-C. It’s the parent class to almost all of the everyday Objective-C classes.

Note: There are some C structs like CGRect and CGSize that don't use NSObject as their parent class, since structs don’t really adhere to Object-Oriented programming. However, the vast majority of classes with the prefix NS or UI have NSObject as their parent class. Check out Apple's documentation to learn more about NSObject.

Note: There are some C structs like CGRect and CGSize that don't use NSObject as their parent class, since structs don’t really adhere to Object-Oriented programming. However, the vast majority of classes with the prefix NS or UI have NSObject as their parent class. Check out Apple's documentation to learn more about NSObject.

To see inheritance in action, create a subclass of Vehicle, “Car”. Go to File\New\File...\Cocoa Touch\Objective-C Class. Then, create a subclass of Vehicle called Car, as shown below:

Add Car

Now open Car.m add the following initialization method under the @implementation line:

- (id)init
{
  if (self = [super init]) {
    // Since all cars have four wheels, we can safely set this for every initialized instance
    // of a car. 
      self.numberOfWheels = 4;
  }
  return self;
}

This init implementation simply sets the number of wheels to 4.

Did you notice that you didn’t have to do anything extra to access the numberOfWheels property of the Vehicle parent class? That’s because by inheriting from the Vehicle class, Car already knows about all of Vehicle’s public properties and methods.

But what if you need more information to describe the car? Cars have more specific characteristics than just the number of wheels How many doors does it have? Is it a hatchback or does it have a normal trunk? Is it a convertible? Does it have a sunroof?

Well, you can easily add those new properties! Open Car.h and add the following new properties under the @interface line:

@property (nonatomic, assign) BOOL isConvertible;
@property (nonatomic, assign) BOOL isHatchback;
@property (nonatomic, assign) BOOL hasSunroof;
@property (nonatomic, assign) NSInteger numberOfDoors;

Contributors

Over 300 content creators. Join our team.