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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Intro to Object-Oriented Design: Part 1/2
40 mins
- Getting Started
- The Basics Of Objects
- A Minor Digression: Under The Hood With Properties
- Describing the Object
- A Minor Digression: Class Methods vs. Instance Methods
- Adding Basic Methods to Your Class
- Inheritance
- Overriding Methods
- Building out the User Interface
- Hooking Your Data to Your View
- Model-View-Controller Encapsulation of Logic
- Creating Subclasses via Inheritance
- Housing Logic in the Model Class
- Where To Go From Here?
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:
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:
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;