Extensions - OOP REVISITED - Understanding Swift Programming: Swift 2 (2015)

Understanding Swift Programming: Swift 2 (2015)

PART 4: OOP REVISITED

33. Extensions

Extensions in Swift allow you to add new functionality to an existing class. (Extensions also work with structures and enumerations.)

Extensions can only add new functionality. They cannot change the behavior of, that is, override, existing functionality. In other words, you can add a new method to an existing class, but you cannot modify the code of an existing method of that class.

It is not possible to use an extension to add a stored property to a class or structure (and enumerations don't have stored properties).

In an environment in which you are dealing with a lot of code with many programmers, it is often considered a good practice to allow the extension of code libraries but not to allow their modification.

Extensions also make it possible to modify classes even when you do not have the source code, so it's possible to extend even basic Swift and other iOS classes.

What can be extended? You can add instance methods, class (type) methods, computed properties, initializers, custom subscripts, and nested types. You can also specify that an existing type now conforms to a protocol.

How do you do an extension? It's pretty simple. You use the same syntax that you would if you were putting the code in the original, just prefaced by the extension keyword and the name of the class (or structure or enumeration) you are extending and with braces surrounding the new code. So if you want to extend the class Fruit:

extension Fruit {

// New code--method, initializer, computed property, etc

}

There is no name for the extension.

If you don't have the source code for a class and want to add something to it you don't have any choice but to use an extension. If you do have the source code, then it's a choice of what makes sense. If you have a package of code that you want to keep well-maintained you might prefer to add things individually for special cases using extensions rather than changing the package of code.

Adding a Method

If I have an existing class named Fruit and I want to add a new method to it called showValueOfHasSeeds, I can do it as follows:

extension Fruit {

func showValueOfHasSeeds() {

if self.hasSeeds {

print("This particular fruit HAS seeds")

}

else {

print("This particular fruit does NOT HAVE seeds")

}

}

}

This method just prints something different depending upon the value of a property of the class Fruit. The class Fruit obviously must already have the stored property hasSeeds defined.

This is an instance method, and is called as follows:

let aParticularPieceOfFruit = Fruit()

aParticularPieceOfFruit.showValueOfHasSeeds() // Prints: This particular fruit does NOT HAVE seeds

Instance methods can be added to structures and enumerations as well as classes. If a method is added to a structure or enumeration that changes a property, it must have the mutating keyword in front of the func keyword.

The class method that was added with the extension can be executed as follows:

Fruit.showNumberOfFruits() // Prints: 27

These examples show how to add an instance and a class (type) method to a class. Adding these kinds of methods to structures and enumerations is done in exactly the same way.

Adding a Computed Property

A computed property, whether it is an instance or a class (type) computed property, involves adding the code that gets executed when the computed property is accessed.

extension Fruit {

var weightInKg:Float {

get {

return weightInLbs*2.20462

}

set (newValue) {

weightInLbs = newValue/2.20462

}

}

}

This is an instance computed property that calculates the weight of a piece of fruit in kilograms, based on the value of the property weightInLbs, which actually stores the value of the weight.

let aPieceOfFruit = Fruit()

aPieceOfFruit.weightInLbs = 0.5

print(aPieceOfFruit.weightInKg) // Prints: 1.10231

This creates an instance of the class Fruit, then sets the value of its weight, expressed in pounds.

The code in the set part of the computed property definition is executed when the print statement references the weightInKg property, which causes the weight in kilograms to be calculated and then printed.

The code can also allow setting the weight of the piece of fruit when expressed in kilograms:

let aPieceOfFruit = Fruit()

aPieceOfFruit.weightInKg = 1.0

This would cause the code in the set part of the computed property definition to be executed, which converts the value and stores it in the property weightInLbs.

A class or type computed property is done in the same way, except that a class or static keyword is added, depending upon whether the original type is a class, structure, or enumeration.

Adding an Initializer

Initializers can be added to a class or structure, but there are limits. Only a convenience initializer can be added to a class, not a designated initializer. Initializers can be added to structures under appropriate conditions.

Adding a Custom Subscript

Custom subscripts can be added that did not exist before. This is done in just the same way that a custom subscript would be added in the original code. They can be added to classes, structures, and enumerations.

Adding Nested Types

Nested types can be added that did not exist before. This is done in just the same way that a nested type would be added in the original code. They can be added to classes, structures, and enumerations.

Indicating Conformance with a Protocol

An extension can indicate that a class (or structure or enumeration) conforms to a particular protocol. This might be the case as a result of adding new functionality that makes the class now conform to a given protocol. It might also happen that an existing class (or structure or enumeration) actually did have the functionality to conform to a given protocol, but the class/structure/enumeration definition did not indicate this conformance.

Protocol Extensions

New in Swift 2, implementations of methods and stored properties can be added to protocols by using an extension. See Chapter 34 on “Protocol Oriented Programming.”

Hands-On Exercises

Go to the following web address with a Macintosh or Windows PC to do the Hands-On Exercises.

For Chapter 33 exercises, go to

understandingswiftprogramming.com/33