Chapter    12

Inheritance, Polymorphism, and Extending Classes

In Chapter 11 you learned how objects were created from classes and how classes define properties and methods. To protect its data and methods from other parts of a program, an object isolates or encapsulates its code. Encapsulation is one prime advantage of object-oriented programming because it creates self-contained code that you can easily modify or replace without affecting any other part of a program.

By keeping code as independent as possible from other parts of a program, objects increase reliability. Think of a house built out of playing cards. Remove one card and the whole thing collapses, which is the way most software worked before object-oriented programming.

Objects are like playing cards that you can remove and replace without affecting any other card. Besides encapsulation, object-oriented programming also includes two additional features called inheritance and polymorphism.

The idea behind inheritance is to reuse existing code without physically making another copy of that code. The idea behind polymorphism is that you can replace inherited code without modifying the original code. Through both inheritance and polymorphism, you can reuse existing code, even without understanding how the original code works.

In fact, each time you create a project in Xcode, look at the top of your Swift files and you should see a line that looks like this:

import Cocoa

This line tells Xcode to use all the classes that Apple has created for you that are stored in the Cocoa framework. In our previous example programs, you used the Cocoa framework to manipulate arrays, sets, and dictionaries. Without the Cocoa framework, you would have to write Swift code to perform these common functions yourself. Not only would this be time consuming, but it would be error prone as well since you would have to write code and then test to make sure it worked.

By simply relying on classes in the Cocoa framework, you can add functionality to your program without writing much code at all. As you get more experienced writing your own classes, you can create useful libraries of your own that you can easily plug into other projects to reuse all your hard work.

Understanding Inheritance

The main purpose of inheritance is to make reusing code easy. In the old days, people reused code by simply making another copy of that code. Now what happens if you find an error (bug) in the code? That means you’ll need to fix that bug in every copy of your code. Miss one copy of the faulty code and your program won’t work.

Creating multiple copies of the same code causes two problems. First, it wastes space. Second, it makes modifying the code harder with multiple copies of code scattered all over a program. Inheritance fixes both problems.

First, inheritance never makes a copy of code so it never wastes space. Second, since inheritance only keeps one copy of code, you just need to modify one copy of code to have your changes automatically affect every part of your program that relies on that code.

Instead of physically copying code, inheritance basically creates pointers or references to one copy of code. When you create a class, you can simply state its name like this:

class className {

}

To inherit code from another class, name that other class like this:

class className : superClass {

}

This code defines a class called “className,” which inherits code from another class called “superClass.” That means any properties and methods defined in “superClass” automatically work in “className” as well, even though the “className” class is completely empty.

If you peek at any of the OS X sample programs you created in earlier chapters, you may see code that looks like this:

class AppDelegate: NSObject, NSApplicationDelegate {

This defines a class called AppDelegate, which inherits code from another class called NSObject. (This code also adds additional code to the AppDelegate class through another file called NSApplicationDelegate, which is a file that you’ll learn more about later in this chapter.)

To see how to use inheritance with classes, create a new playground by following these steps:

  1. Start Xcode.
  2. Choose File image New image Playground. (If you see the Xcode welcome screen, you can also click on Get started with a playground.) Xcode asks for a playground name and platform.
  3. Click in the Name text field and type InheritPlayground.
  4. Click in the Platform pop-up menu and choose OS X. Xcode asks where you want to save your playground file.
  5. Click on a folder where you want to save your playground file and click the Create button. Xcode displays the playground file.
  6. Edit the code as follows:
      import Cocoa

    class firstClass {
        var speed : Int = 0
        var locationX : Int = 3
        var locationY : Int = 5
        func move (X: Int, Y: Int) {
            locationX += X
            locationY += Y
        }
    }

    class copyCat : firstClass {

    }

    var kitten = copyCat ()
    kitten.speed = 4
    kitten.move(4, Y: 8)
    print (kitten.locationX)
    print (kitten.locationY)

This Swift code defines two classes. First, it defines a class (called firstClass) that has three properties (speed, locationX, and locationY) and one method (move). Then it defines a second class (called copycat) that’s completely empty, but it inherits all the code from firstClass.

To show that the copyCat class inherits code from firstClass, the Swift code next creates an object called “kitten,” which is based on the copyCat class. The kitten object can store data in a speed property and use the move method to change its locationX and locationY properties, yet the copyCat class is completely empty. Figure 12-1 shows the results of running this Swift code in a playground.

9781484212349_Fig12-01.jpg

Figure 12-1. Showing how inheritance works

 Note  Some programming languages, such as C++, allow one class to inherit from two or more classes, which is known as multiple inheritance. However in Swift, a class can only inherit from only one other class, which is known as single inheritance.

In the above example, the copyCat class inherits three properties (speed, locationX, and locationY) and one method (move) from firstClass. Since the copyCat class didn’t define any properties or methods of its own, the copyCat class is basically identical to firstClass.

In actual use, there’s no reason for a class to inherit from another class as an exact duplicate. Instead, it’s more common for one class (known as the subclass) to inherit from another class (known as the superclass) and then add additional properties and methods of its own.

In this way, the subclass only needs to include the code for these new properties and methods while still having access to all the properties and methods of the superclass. For example, consider the following class:

class copyDog : copyCat {
    var name : String = ""
}

This class inherits all the code from the copyCat class and adds one new property of its own called “name” that can hold a string. The above class definition that defines a name property and inherits code from the copyCat class is equivalent to the following:

class copyDog {
    var speed : Int = 0
    var locationX : Int = 3
    var locationY : Int = 5
    func move (X: Int, Y: Int) {
        locationX += X
        locationY += Y
    }
    var name : String = ""
}

Remember, the copyCat class inherited everything from firstClass, which defined the speed, locationX, and locationY properties along with the move method. In comparison, the copyDog class that inherits code from the copyCat class is much shorter and simpler.

Inheritance works like a daisy chain. If class A inherits from class B, but class B inherits everything from class C, then class A inherits everything from both class B and class C. For example, the copyDog class inherits everything from the copyCat class. The copyCat class, in turn, inherits everything from firstClass. That means the copyDog class ultimately inherits everything from both the copyCat class and firstClass as shown in Figure 12-2 .

9781484212349_Fig12-02.jpg

Figure 12-2. Classes inherit everything from previous classes

This daisy chain effect of inheritance is how the Cocoa framework is designed. At its simplest level, there’s a basic class called NSObject. A class such as NSResponder inherits everything from NSObject and adds new properties and methods of its own. Another class such as NSView inherits everything from NSResponder and NSObject. When you look up classes in the Cocoa framework in Xcode’s Documentation window, you can see this daisy chain link of classes identified by the “Inherits from:” label as shown in Figure 12-3.

9781484212349_Fig12-03.jpg

Figure 12-3. The Documentation window identifies the superclasses that the currently displayed class inherits from

To see how to use inheritance works between multiple classes, follow these steps:

  1. Make sure the InheritPlayground file is loaded in Xcode.
  2. Edit the code as follows:
    import Cocoa

    class animal {
        var legs : Int = 0
    }

    class packAnimal : animal {
        var strength : Int = 100
    }

    class biped : packAnimal {
        var IQ : Int = 75
    }

    var snake = animal()
    print (snake.legs)

    var mule = packAnimal()
    mule.legs = 4
    mule.strength = 120

    var relative = biped()
    relative.legs = 2
    relative.strength = 55
    relative.IQ = 10

This code creates three classes: animal (legs property), packAnimal (strength property), and biped (IQ property). Then it creates three objects based on these classes. The first object, snake, is based on the animal class. The second object, mule, is based on the packAnimal class. The third object, relative, is based on the biped class.

Ultimately the relative object contains properties from all three classes, the mule object only contains properties from the animal and packAnimal class, and the snake object only contains properties from the animal class as follows:

Object

Based on these classes

Contains these properties

snake

animal

legs

mule

packAnimal, animal

legs, strength

relative

biped, packAnimal, animal

legs, strength, IQ

The snake, mule, and relative objects contain different properties based on their different classes and the classes that they inherit from as shown in Figure 12-4.

9781484212349_Fig12-04.jpg

Figure 12-4. Seeing how inheritance works among properties stored in different classes

Understanding Polymorphism

When one class (subclass) inherits from another class (superclass), it contains all the properties and methods stored in the superclass. Although a subclass inherits all properties and methods from a superclass, those properties and methods aren’t displayed inside the subclass. The only code that appears in each class are properties and methods unique to that class.

Properties inherited from another class retain the same name and data type. Methods inherited from another class retain the same method name and code that makes it do something useful.

The problem with inheriting methods is that you may want to modify the code in an inherited method. For example, suppose you had a video game where you have dogs running on the ground and birds flying in the air. You could create a basic class like this:

  class gameObject {
    var speed : Int = 0
    var locationX : Int = 3
    var locationY : Int = 3
    func move (X: Int, Y: Int) {
        locationX += X + speed
        locationY += Y + speed
    }
}

var dog = gameObject()

Now the dog object, created from the gameObject class, has three properties (speed, locationX, and locationY) and one method (move) that change the locationX and locationY properties.

A dog can only run on the ground, but a bird can move in two dimensions, so it needs an additional height property. To move a flying object, the move method needs to change the height property. That means the move method needs to be different.

One clumsy way around this problem is to create a different name for the move method such as changing its name form “move” to “fly”:

class flyingObject : gameObject {
    var height : Int = 0
       func fly (X: Int, Y: Int) {
        locationX += X + speed
        locationY += Y + speed
        height += (X + Y) / 2
    }
}

var bird = flyingObject()

The problem with this solution is that the bird object, created from the flyingObject class, now has two methods: the move method inherited from gameObject and the new fly method defined in flyingObject.

You could simply ignore the move method and use the fly method, but that risks creating errors if you accidentally use the move method to change the position of a bird instead of the correct fly method that moves a bird in two dimensions instead of one.

That’s why polymorphism exists. Polymorphism basically lets you reuse a method name (such as move) but replace it with completely different code to make it work. To identify when you’re using polymorphism to reuse a method name but modify its code, you must use the “override” keyword in front of the method you’re changing such as:

override func move (X: Int, Y: Int) {
    locationX += X + speed
    locationY += Y + speed
    height += (X + Y) / 2
}

When you override a method (use polymorphism), you essentially have two identically named methods, but one version is defined in one class and the second version is defined in another class. The computer never gets confused because you can only run each method by specifying both the object name and the method name. Even though the method names are identical, the object names are not.

To see how polymorphism works, follow these steps:

  1. Make sure your InheritPlayground file is loaded into Xcode.
  2. Edit the code as follows:
    import Cocoa

    class gameObject {
        var speed : Int = 0
        var locationX : Int = 3
        var locationY : Int = 3
        func move (X: Int, Y: Int) {
            locationX += X + speed
            locationY += Y + speed
        }
    }

    var dog = gameObject()

    class flyingObject : gameObject {
        var height : Int = 0
        override func move (X: Int, Y: Int) {
            locationX += X + speed
            locationY += Y + speed
            height += (X + Y) / 2
        }
    }

    var bird = flyingObject()

    dog.move (4, Y: 7)
    bird.move (4, Y: 7)

To override a method, the flying Object class must first inherit from another class. In this case flyingObject inherits from gameObject. Now the flyingObject class can use the “override” keyword to specify that it’s changing the code that makes the move method work. In this case, the only change was adding code to modify the height property, but we could have added completely different code inside the overridden move method.

Notice that when you run the move method for the dog object (dog.move), the move method only changes the values of locationX and locationY, but when you run the move method for the bird object (bird.move), the overridden method runs and also changes the height property as shown in Figure 12-5.

9781484212349_Fig12-05.jpg

Figure 12-5. Overridden methods can behave differently

When overriding methods, you can only change the code inside the method. You cannot change the parameter list of the method. For example, consider this class:

class basicDesign {
    var location : Int = 0
    func moveMe (X : Int) {
        location += X
    }
}

To override the moveMe method, this next class needs to inherit from the basicDesign class and change only the code inside the overridden method. The following would not work:

class newDesign : basicDesign {
    override func moveMe (X: Int, Y: Int) { // Does NOT work

    }
}

Notice that the original moveMe method only has one parameter (X : Int), but the moveMe method in the newDesign class has two parameters (X: Int, Y: Int). Despite having the same name, this method has a different parameter list so it won’t work. When overriding methods, you can only change the code, not the parameter list.

Overriding Properties

Besides overriding methods, Swift also lets you override properties. When you override properties, you must keep the same property name and data type. What you can change are the getters and setters along with the property observers of a variable.

At the simplest level, a getter simply returns a value of a variable. On a more sophisticated level, a getter calculates a value. Consider the following:

class basicDesign {
    var location: Int {
        get {
            return 4
        }
    }
}

This basicDesign class defines a single property called location with a getter that returns the value 4 in the location property. To override this property, you need to retain the variable name and data type (Int), but you can change the getter code such as:

class newDesign : basicDesign {
    override var location: Int {
        get {
            return 7
        }
    }
}

This newDesign class inherits the location property from the basicDesign class. However it overrides the location property with a new getter that returns a value of 7.

To see how overriding properties work, follow these steps:

  1. Make sure your InheritPlayground file is loaded into Xcode.
  2. Edit the code as follows:
    import Cocoa

    class basicDesign {
        var location: Int {
            get {
                return 4
            }
        }
    }

    class newDesign : basicDesign {
        override var location: Int {
            get {
                return 7
            }
        }
    }

    var ant = basicDesign()
    var fly = newDesign()
    ant.location
    fly.location

In this example, the ant object is based on the basicDesign class, which defines the location property with a value of 4. The fly object is based on the newDesign class, which inherits the location property. However, the newDesign class overrides the location property’s getter code so instead of storing a value of 4 in the location property, it stores a value of 7, instead, as shown in Figure 12-6.

9781484212349_Fig12-06.jpg

Figure 12-6. Overriding properties with new getter code

Remember, when overriding methods and properties, you can only change:

  • code in the method
  • code in the property’s getter/setter or property observer

You can never change the:

  • method name
  • method parameter list
  • property name
  • property data type

Preventing Polymorphism

In some cases, you may want to prevent a method, property, or even an entire class from being modified through polymorphism. To do this, you just need to insert the “final” keyword. If you wanted to prevent an entire class from being inherited, just put the “final” keyword in front of the class name like this:

final class className {
         var propertyName = initialValue
         func methodName() {

        }
}

 Note  If you place “final” in front of a class name, it automatically prevents that class’s properties and methods from being overridden so you don’t need to place “final” in front of each property or method name.

If you wanted to prevent an individual property or method from being overridden, just place the “final” keyword in front of the property or method like this:

class className {
         final var propertyName = initialValue
         func methodName() {

        }
}

The “final” keyword in the above example prevents the property from being overridden while allowing the method to be overridden. If you wanted to prevent the method from being overridden while allowing the property to be overridden, you would place the “final” keyword in front of the method like this:

class className {
         var propertyName = initialValue
         final func methodName() {

        }
}

Using Extensions

If there’s a class that contains the properties and methods you need, the object-oriented approach is to inherit from that class (create a subclass). The problem with constantly creating subclasses is that it can get awkward to create objects from slightly different class files.

This can be especially true when you want to extend the features of classes that are part of the Cocoa framework. For example, if you’re working with String data types, you probably don’t want to

create a subclass of the String data type and then create objects based on this new subclass. Ideally, you want to continue using String data types but have added features as well.

That’s why Swift offers extensions. Extensions essentially let you add code to an existing class without creating a subclass. That way you can still get to use the original class but you also get to add new features to that class without going through inheritance, polymorphism, or subclasses. The structure of an extension looks like this:

extension className {

}

Extensions can define methods along with properties that contain code such as:

  • getters and setters
  • initializers
  • property observers

While extensions add new properties methods to a class without inheritance, extensions cannot override existing methods or properties in a class. Extensions also can’t create properties assigned an initial value such as:

var temperature : Int = 100        // Cannot be used in an extension

To see how to an extension can add properties and methods to a class, create a new playground by following these steps:

  1. Start Xcode.
  2. Choose File image New image Playground. (If you see the Xcode welcome screen, you can also click on Get started with a playground.) Xcode asks for a playground name and platform.
  3. Click in the Name text field and type ExtensionPlayground.
  4. Click in the Platform pop-up menu and choose OS X. Xcode asks where you want to save your playground file.
  5. Click on a folder where you want to save your playground file and click the Create button. Xcode displays the playground file.
  6. Edit the code as follows:
    import Cocoa

    class emptyClass {

    }

    extension emptyClass {
        var age : Int {
            get {
                return 50
            }
        }
        func retire (testAge : Int) -> String {
            if testAge < 62 {
                return "Keep working"
            } else {
                return "Time to retire"
            }
        }
    }

    var aWorker = emptyClass ()
    aWorker.retire(65)
    aWorker.age

This code creates a completely empty class, then creates an extension that adds an “age” property and a “retire” method to the empty class. Finally, it creates an object from that empty class, calls the “retire” method (defined in the extension) and displays the value stored in the “age” property as shown in Figure 12-7.

9781484212349_Fig12-07.jpg

Figure 12-7. Using an extension to add a property and method to an empty class

You can see that the class itself does nothing, but with extensions, the class now gets added features that it didn’t have before.

Using Protocols

In the beginning of this chapter, you were first introduced to something that appears in the class AppDelegate.swift file that you’ve been creating to learn the basic principles of each chapter. This class AppDelegate declaration looks like this:

class AppDelegate: NSObject, NSApplicationDelegate {

This line of code creates a class called AppDelegate, which inherits properties and methods from the NSObject class that’s part of the Cocoa framework. However, the NSApplicationDelegate is the name of another file used to extend classes without going through inheritance or subclasses.

The NSApplicationDelegate file is a protocol file. The above Swift code creates a class called AppDelegate, inherits properties and methods from the NSObject class, and also inherits code from the NSApplicationDelegate file. (You can see more details about the NSApplicationDelegate protocol by viewing it in the Xcode Documentation window.)

The main difference between a class (such as NSObject) and a protocol (such as NSApplicationDelegate) is that a class defines properties and methods while a protocol only defines properties and method names without any code that actually implements them. A protocol is sometimes called an empty class because it never defines any Swift code to make anything actually work.

A protocol defines a group of property and method names for solving a particular type of problem. Now it’s up to the class that adopts or conforms to this protocol to provide the actual Swift code that implements each method or property declaration.

A protocol declaration looks identical to a class or structure declaration. The only difference is that a protocol declaration uses the “protocol” keyword:

protocol protocolName {

}

Within this protocol declaration you can define properties and methods without implementing any Swift code like this:

protocol protocolName {
    var property1 : datatype { get }        // read-only
    var property2 : datatype { get set }    // read-write
    func methodName (parameters) -> datatype
}

When a protocol defines a property or method, any class that adopts that protocol must implement that property or method exactly as its defined in the protocol. In the above example, property1 is defined with a getter and property2 is defined with a getter and a setter.

That means when a class implements those two properties, it must define a getter only for property1 and both a getter and a setter for property2.

Likewise, the method defined in the protocol must be exact when adopted in the class file. That means if the method is defined in the protocol with two integer parameters, then the implementation of that method must also have the exact same two integer parameters.

Protocols are generally used when working with common user interface items that require specific types of methods to manipulate them, but can’t define exactly how to manipulate them because the data may differ from one program to another.

For example, table views are a user interface item that displays a list of data in rows. The table view needs to know how many rows of data to hold and what type of data to display in each row. Since every table view needs to know this information, it makes sense to create standard methods to do this, but since every table view needs to contain different information, it also makes sense to avoid writing Swift code to actually fill a table view with data.

Any program that includes a table view can take advantage of predefined method names stored in a protocol for manipulating data. All you need to do is add Swift code to fill the table view with data.

By using protocols, you can manipulate table views using identical method names from one program to another. Without table view protocols, you’d be forced to make up your own method names for adding and displaying data in a table view. Thus protocols are typically used in the Cocoa framework to provide a consistent list of methods for performing common tasks.

To see how protocols work, follow these steps:

  1. Make sure the ExtensionPlayground file is loaded into Xcode.
  2. Edit the code as follows:
    import Cocoa

    protocol testMe {
        var cash : Int { get }
        var creditCheck : Int { get set }
        func purchase (price : Int) -> String
    }

    class windowShopper : testMe {
        var tempValue : Int = 0

        var cash : Int = 0
        var creditCheck : Int {
            get {
                return tempValue
            }
            set (newValue) {
                tempValue = newValue
                cash -= 10
            }
        }
        func purchase (price : Int) -> String {
            cash -= price
            return "Bought something!"
        }
    }

    var shopper = windowShopper ()
    shopper.cash = 450
    shopper.purchase (129)
    shopper.cash

Notice that the testMe protocol defines two properties and a method. The “cash” property is defined only with a getter. The “creditCheck” property is defined with both a getter and a setter. The “purchase” method only lists its parameters (“price” as an integer) and its return value, which is a String. Notice that the protocol doesn’t actually implement any of the necessary Swift code.

When the windowShopper class is created, it adopts or conforms to the testMe protocol. That means it must provide Swift code to define the getter for the “cash” property and the getter and setter for the “creditCheck” property. It will also need to implement the Swift code for the “purchase” method.

If you fail to write Swift code for all the properties and methods defined in the testMe protocol, Xcode will give an error saying the windowShopper class failed to conform to the protocol. When adopting a protocol, make sure you implement all the necessary properties and methods.

Running the above code displays the results as shown in Figure 12-8.

9781484212349_Fig12-08.jpg

Figure 12-8. A class conforming to a protocol

Defining Optional Methods and Properties in Protocols

When you create a protocol, every property and method you define must be implemented by any class that adopts that protocol. However, you can also make one or more properties and methods optional so they can be ignored. To define optional properties or methods, you need to identify the protocol with the @objc keyword and identify individual properties or methods with the “optional” keyword as well such as:

@objc protocol protocolName {
    var requiredProperty : dataType { get }
    optional var optionalProperty : dataType { get }
    optional func optionalMethod ()
}

To adopt or conform to this protocol, a class only needs to implement any property or method that is not identified by the “optional” keyword. To implement required properties or methods, you need to identify them with the @objc keyword such as:

class className : protocolName {
    @objc var requiredProperty : dataType = initialValue
}

However, if you want to implement an optional property or method, you can omit the @objc keyword like this:

class className : protocolName {
    @objc var requiredProperty : dataType = initialValue
        var optionalProperty : dataType = initialValue
}

To see how to create optional properties and methods in a protocol, follow these steps:

  1. Make sure the ExtensionPlayground file is loaded into Xcode.
  2. Edit the code as follows:
    import Cocoa

    @objc protocol person {
        var name : String { get }
        optional var age : Int { get }
        optional func move (X: Int) -> Int
    }

    class politician : person {
        @objc var name : String = ""
    }

    var candidate = politician ()
    candidate.name = "John Doe"

Notice that the only required item in the person protocol defined above is the property “name.” That’s why the politician class only needs to implement the “name” property, but it must identify it with the @objc keyword.

Try experimenting with making different properties and methods optional so you can see how they affect how you need to implement them in the class.

Using Inheritance with Protocols

Protocols can even inherit properties and methods from other protocols. This lets one protocol inherit properties and methods from multiple protocols. Now a class must adopt or conform to all the properties and methods defined in all the protocols.

To see how to inherit properties and methods from multiple protocols, follow these steps:

  1. Make sure the ExtensionPlayground file is loaded into Xcode.
  2. Edit the code as follows:
    import Cocoa

    protocol first {
        var name : String { get }
    }

    protocol second {
        var ID : Int { get }
    }

    protocol third: first, second {
        var email : String { get }
    }

    class inheritProtocols : third {
        var name : String = ""
        var ID : Int = 0
        var email : String = ""
    }

    var friend = inheritProtocols()
    friend.name = "Cindy Smith"
    friend.ID = 12
    friend.email = "[email protected]"

In this example, the “name,” “ID,” and “email” properties are defined in three different protocols. The third protocol inherits from the first and second protocol.

Now when a class adopts the last protocol, it must implement the properties and methods stored in all the protocols. Even though the “name,” “ID,” and “email” properties were all declared in different protocols, the inheritProtocols class can access them all as shown in Figure 12-9.

9781484212349_Fig12-09.jpg

Figure 12-9. Inheriting properties and methods from multiple protocols

Using Delegates

Protocols are closely related to delegation. The main idea behind delegation is for a class to hand off or delegate responsibility to code stored in another class. So rather than create a new subclass to add new features, you can use a delegate that contains additional features.

One common way to use delegates is to allow the view (the user interface) to communicate to the controller. Normally the controller communicates to the view through IBOutlets that allow the controller to display data on the user interface or retrieve data from the user interface.

However, the view can also communicate back to the controller through protocols. The protocol file defines methods and delegates the responsibility to the controller for implementing those methods. The most common types of methods the controller implements involve method names that include will, should, and did such as applicationDidFinishLaunching or applicationWillTerminate.

Figure 12-10 shows how the controller communicates to the view through IBOutlets and the view communicates with the controller through protocols.

9781484212349_Fig12-10.jpg

Figure 12-10. Views can communicate to controllers through protocols

To see how a view uses delegates to communicate with the controller, follow these steps:

  1. From within Xcode choose File image New image Project.
  2. Click Application under the OS X category.
  3. Click Cocoa Application and click the Next button. Xcode now asks for a product name.
  4. Click in the Product Name text field and type DelegateProgram.
  5. Make sure the Language pop-up menu displays Swift and that no check boxes are selected.
  6. Click the Next button. Xcode asks where you want to store the project.
  7. Choose a folder to store your project and click the Create button.
  8. Click the AppDelegate.swift file in the Project Navigator. The contents of the AppDelegate.swift file appears in the middle of the Xcode window. Look for the following line of code:
    class AppDelegate: NSObject, NSApplicationDelegate {

    This line defines a class called AppDelegate that inherits properties and methods from the NSObject class. In addition, it also adopts any properties and methods defined by the NSApplicationDelegate file.

  9. Hold down the Option key and click the mouse over NSObject. When the mouse pointer turns into a question mark, click over NSObject to make a pop-up window appear as shown in Figure 12-11.

    9781484212349_Fig12-11.jpg

    Figure 12-11. Option-clicking on a class name displays information about that class

  10. Release the Option key and click the mouse over NSObject Class Reference at the bottom of the pop-up window. The Documentation window appears, showing details about the different properties and methods available in the NSObject class as shown in Figure 12-12. All those properties and methods are also available in your AppDelegate class as well.

    9781484212349_Fig12-12.jpg

    Figure 12-12. The Documentation window displaying information about the NSObject class

  11. Click the close button (the red dot) in the upper left corner of the Documentation window to make it go away.
  12. Hold down the Option key and click the mouse over NSApplicationDelegate. When the mouse pointer turns into a question mark, click over NSApplicationDelegate to make a pop-up window appear as shown in Figure 12-13.

    9781484212349_Fig12-13.jpg

    Figure 12-13. Option-clicking displays information about the NSApplication protocol

  13. Release the Option key and click the mouse over NSApplicationDelegate Protocol Reference at the bottom of the pop-up window. The Documentation window appears, showing details about the NSApplicationDelegate Protocol as shown in Figure 12-14. Notice that two methods that the NSApplicationDelegate protocol defines are called applicationDidFinishLaunching and applicationWillTerminate.

    9781484212349_Fig12-14.jpg

    Figure 12-14. Viewing the NSApplicationDelegate protocol in the Documentation window

  14. Click the close button (the red dot) in the upper left corner of the Documentation window to make it go away. The Xcode window appears again. Notice that the AppDelegate.swift file contains two empty functions called applicationDidFinishLaunching and applicationWillTerminate. These are defined by the NSApplicationDelegate protocol file but implemented in the AppDelegate.swift file.
  15. Modify both of these functions as follows:
    func applicationDidFinishLaunching(aNotification: NSNotification) {
        print ("This line should print after the program runs")
    }

    func applicationWillTerminate(aNotification: NSNotification) {
        print ("This line should print before your program stops")
    }
  16. Choose Product image Run. Xcode runs your DelegateProgram project and displays an empty user interface.
  17. Choose DelegateProgram image Quit DelegateProgram. The Xcode window appears. The Debug Area at the bottom of the Xcode window now displays the text that the two println commands printed. Notice that the println command inside the applicationDidFinishLaunching function ran first as shown in Figure 12-15.

    9781484212349_Fig12-15.jpg

    Figure 12-15. The methods defined by the NSApplicationDelegate file tell the program what the user interface is doing

Using Inheritance in an OS X Program

Inheritance lets you create method names that remain the same while the underlying code changes between two classes. In this sample program, you’ll define one class and then inherit properties and methods for a second class. This second class will also override a method and add code to make that overridden method behave slightly differently.

To create the sample program that shows how inheritance works, follow these steps:

  1. From within Xcode choose File image New image Project.
  2. Click Application under the OS X category.
  3. Click Cocoa Application and click the Next button. Xcode now asks for a product name.
  4. Click in the Product Name text field and type InheritProgram.
  5. Make sure the Language pop-up menu displays Swift and that no check boxes are selected.
  6. Click the Next button. Xcode asks where you want to store the project.
  7. Choose a folder to store your project and click the Create button.
  8. Click the MainMenu.xib file in the Project Navigator.
  9. Click on the StructureProgram icon to make the window of the user interface appear.
  10. Choose View image Utilities image Show Object Library to make the Object Library appear in the bottom right corner of the Xcode window.
  11. Drag one Push Button and two Labels on the user interface and double-click on the push buttons and labels to change the text that appears on them so that it looks similar to Figure 12-16.

9781484212349_Fig12-16.jpg

Figure 12-16. The user interface of the InheritProgram

This user interface displays two labels that represent two different objects. Object 1 only contains one property and a method to alter that property. Object 2 inherits from Object 1 and contains one additional property along with overriding the method defined in Object 1.

When you click the Change button, both labels will change their appearance based on the properties and method defined by each object. To connect your user interface to your Swift code, follow these steps:

  1. With your user interface still visible in the Xcode window, choose View image Assistant Editor image Show Assistant Editor. The AppDelegate.swift file appears next to the user interface.
  2. Move the mouse over the Change button, hold down the Control key, and drag just above the last curly bracket at the bottom of the AppDelegate.swift file.
  3. Release the mouse and the Control key. A pop-up window appears.
  4. Click in the Connection pop-up menu and choose Action.
  5. Click in the Name text field and type changeButton.
  6. Click in the Type pop-up menu and choose NSButton. Then click the Connect button. Xcode creates an empty IBAction method called changeButton.
  7. Move the mouse over the Object 1 label, hold down the Control key, and drag below the @IBOutlet line in the AppDelegate.swift file.
  8. Release the mouse and the Control key. A po-pup window appears.
  9. Click in the Name text field and type ObjectOne and click the Connect button.
  10. Move the mouse over the Object 2 label, hold down the Control key, and drag below the @IBOutlet line in the AppDelegate.swift file.
  11. Release the mouse and the Control key. A pop-up window appears.
  12. Click in the Name text field and type ObjectTwo and click the Connect button. You should now have the following IBOutlets that represent all the labels on your user interface:
    @IBOutlet weak var window: NSWindow!
    @IBOutlet weak var ObjectOne: NSTextField!
    @IBOutlet weak var ObjectTwo: NSTextField!
  13. Type the following directly underneath the IBOutlet lines of code:
    class one {
        var myColor : NSColor = NSColor.blackColor ()
        func change () {
            myColor = NSColor.redColor()
        }
    }

    class two : one {
        var myBackground : NSColor = NSColor.whiteColor()
        override func change() {
            myColor = NSColor.blueColor()
            myBackground = NSColor.greenColor()
        }
    }
    var ThingOne = one ()
    var ThingTwo = two()
  14. Modify the IBAction changeButton method as follows:
    @IBAction func changeButton(sender: NSButton) {
        ThingOne.change()
        ThingTwo.change()
        ObjectOne.textColor = ThingOne.myColor
        ObjectTwo.textColor = ThingTwo.myColor
        ObjectTwo.drawsBackground = true
        ObjectTwo.backgroundColor = ThingTwo.myBackground
    }

This IBAction method runs the change method in both the ThingOne and ThingTwo objects, which are based on the one and two classes respectively. The two class inherits from the one class, but overrides the change method to modify an additional property called myBackground.

After both ThingOne and ThingTwo change their properties, the first label (represented by ObjectOne) assigns its text color to the myColor property from the ThingOne object. The second label (represented by ObjectTwo) changed its myColor and myBackground properties, so it sets those properties to the label.

The complete contents of the AppDelegate.swift file should look like this:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!
    @IBOutlet weak var ObjectOne: NSTextField!
    @IBOutlet weak var ObjectTwo: NSTextField!

    class one {
        var myColor : NSColor = NSColor.blackColor ()
        func change () {
            myColor = NSColor.redColor()
        }
    }

    class two : one {
        var myBackground : NSColor = NSColor.whiteColor()
        override func change() {
            myColor = NSColor.blueColor()
            myBackground = NSColor.greenColor()
        }
    }

    var ThingOne = one ()
    var ThingTwo = two()

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        // Insert code here to initialize your application
    }

    func applicationWillTerminate(aNotification: NSNotification) {
        // Insert code here to tear down your application
    }

    @IBAction func changeButton(sender: NSButton) {
        ThingOne.change()
        ThingTwo.change()
        ObjectOne.textColor = ThingOne.myColor
        ObjectTwo.textColor = ThingTwo.myColor
        ObjectTwo.drawsBackground = true
        ObjectTwo.backgroundColor = ThingTwo.myBackground
    }
}

To see how this program works, follow these steps:

  1. Choose Product image Run. Xcode runs your InheritProgram project. Notice that both labels look identical.
  2. Click the Change button. The Object 1 label only changes its text color because it represented a class that only has one property (myColor). The Object 2 label changes both its text color and its background color because it has two properties (myColor and myBackground). Even though the change method name is identical in both classes, it’s been overridden in the second class to modify the myBackground property.

    9781484212349_Fig12-17.jpg

    Figure 12-17. Clicking the Change button modifies two different objects with the same method name

  3. Choose InheritProgram image Quit InheritProgram.

Summary

Classes let you organize related code together where data (properties) and functions (methods) to manipulate that data are stored in the same place. The most straightforward way to extend the features of a class is through inheritance where you create a subclass.

Inheritance lets you inherit all the properties and methods of another class. A class can only inherit from one other class, but it’s possible for that other class to inherit from another class as well, creating a daisy-chain effect of classes inheriting from other classes. The Cocoa framework is based on this idea of inheritance among daisy chains of classes.

To block inheritance, you can use the “final” keyword. To identify when you’re overriding a property or method, you need to use the “override” keyword.

Beyond inheritance, you can also extend the features of a class through extensions and protocols. Protocols are commonly used with the Cocoa framework to extend the features of a class. Through inheritance, extensions, and protocols, you can extend the features of any class to make it easy to reuse existing code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset