Intro to Object-Oriented Design in Swift: Part 1/2

Learn the basics of object-oriented design in Swift. In this first part, you’ll learn about objects and classes, inheritance, and the Model-View-Controller relationship. By Ray Fix.

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.

Adding Basic Methods to Your Class

Still in Vehicle.swift, add the following methods to your Vehicle class.

func goForward() -> String {
  return "null"
}
  
func goBackward() -> String {
  return "null"
}
  
func stopMoving() -> String {
  return "null"
}
  
func turn(degrees:Int) -> String {
  var normalizedDegrees = degrees
    
  //Since there are only 360 degrees in a circle, calculate what a single turn would be.
  let degreesInACircle = 360
  
  if (normalizedDegrees > degreesInACircle || normalizedDegrees < -degreesInACircle) {
    // The % operator returns the remainder after dividing.
    normalizedDegrees = normalizedDegrees % degreesInACircle
  }
  
  return String(format: "Turn %d degrees.", normalizedDegrees)
}
  
func changeGears(newGearName:String) -> String {
  return String(format: "Put %@ into %@ gear.",self.modelName, newGearName)
}
  
func makeNoise() -> String {
  return "null"
}

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.swift, and replace the implementation of application(_:didFinishLaunchingWithOptions:) with the following:

func application(application: UIApplication, 
                 didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    
  var vehicle = Vehicle()
  // Test methods with implementations
  println("Vehicle turn: \(vehicle.turn(700))")
  var changeGearResult = vehicle.changeGears("Test")
  println("Vehicle change gears: \(changeGearResult)")
    
  // Test methods without implementations
  println("Vehicle make noise: \(vehicle.makeNoise())")
  println("Vehicle go forward: \(vehicle.goForward())")
  println("Vehicle go backward: \(vehicle.goBackward())")
  println("Vehicle stop moving: \(vehicle.stopMoving())")
    
  return true
}

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. Since you have put in placeholder values for most of the properties, you will see this in the debug console:

Debugger

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 Swift. 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.

To see inheritance in action, create a subclass of Vehicle called Car. Go to File\New\File… and select iOS\Source\Swift File. Name the file Car.

Now open Car.swift and add the following class definition for Car:

class Car : Vehicle { 
  override init() {
    super.init()
    numberOfWheels = 4
  }
}

Car derives from your Vehicle class and inherits all of its methods and properties. Note that it makes perfect sense to say, “A Car is-a Vehicle“. If you can naturally say, “Subclass is-a Superclass”, derivation usually makes sense.

Since you provided values for all of the properties in the superclass, there’s no need to explicitly set each in your subclass. You may only want to set certain properties and leave the others as their defaults. For Cars, we know that the numberOfWheels will be four. To express this you override the initializer, call the superclass initializer, and then customize the numberOfWheels property to four. The order is significant. If you called super.init() last, numberOfWheels would get reset back to 0. Fortunately, the Swift complier will not allow you to make this mistake.

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! In Car.swift, above your initializer, add:

var isConvertible:Bool = false
var isHatchback:Bool = false
var hasSunroof:Bool = false
var numberOfDoors:Int = 0

Now, any Car object can be customized with all properties from the Vehicle and Car classes.

Overriding Methods

Now that you’ve added the appropriate additional properties, you can override several methods from the superclass to provide full implementations of those methods.

Overriding a method means “taking a method declared in the superclass and creating your own implementation.” 

For example, when you add a new UIViewController object, it already comes with overridden methods for viewDidLoad and others. In Swift, when you override a method, you must use the override keyword. This communicates your intent to the compiler. If you accidentally misspell a method parameter, for example, the compiler can let you know that something is wrong. Also, if you didn’t know you were overriding a method, the compiler will also let you know.

Unlike an initializer method, when you override a normal method, you can do one of two things:

  1. Include a call to the super.method() to take advantage of everything happening higher up the inheritance chain, or
  2. Provide your own implementation from scratch.

In all of the UIViewController methods, you can tell that Apple wants you to call the [super method] – there’s some important stuff in there that needs to execute before your UIViewController subclass can do its work.

However, since most of the methods you’re going to override in the Car class are returning empty values, you can just create your own implementations. There’s nothing useful in the superclass’s implementation so there’s no need to call it.

Still in Car.swift add the following private helper method to simplify your superclass override:

// MARK: - Private method implementations
private func start() -> String {
  return String(format: "Start power source %@.", powerSource)
}

Some vehicles such as bicycles don’t need to be started, but cars do! Here you use the access control keyword private to express the fact that this method should not be used outside of this file.

Note: Although this tutorial does not cover access control in detail, using it is pretty simple. If you do not add any access control keywords, the class, method or property defaults to internal and can be used by any code in the same module. If you use private, access is limited to the file. If you use public, you can access from anywhere, including outside the module. This is useful if you are building a framework, to be used by other projects, for example.

Next, add the remaining superclass overrides:

// MARK: - Superclass Overrides
override func goForward() -> String {
  return String(format: "%@ %@ Then depress gas pedal.", start(), changeGears("Forward"))
}
  
override func goBackward() -> String {
  return String(format: "%@ %@ Check your rear view mirror. Then depress gas pedal.", start(), changeGears("Reverse"))
}
  
override func stopMoving() -> String {
  return String(format: "Depress brake pedal. %@", changeGears("Park"))
}
  
override func makeNoise() -> String {
  return "Beep beep!"
}

Now that you have a concrete, or fully implemented, subclass of Vehicle, you can start building out your Table View controller.

Contributors

Ray Fix

Author

Over 300 content creators. Join our team.