Custom Subscripts - ADDITIONAL TOPICS - Understanding Swift Programming: Swift 2 (2015)

Understanding Swift Programming: Swift 2 (2015)

PART 3: ADDITIONAL TOPICS

24. Custom Subscripts

It is often the case that subscripts are useful for quickly and easily accessing data that is stored in the form of an array, string, or dictionary. Thus, in the example below we can quickly access the second item in the array airplanes with the expression airplanes[1]:

let airplanes = ["Boeing 777", "Airbus 320", "Beechcraft Bonanza"]

print(airplanes[1])

In this case the second statement would print out "Airbus 320".

(As in most languages the index to an array starts at 0.)

A subscript is just an identifier that is contained within square brackets. The value used in a subscript is often an integer, as seen above, but it can also be a string, and a string is often used with a dictionary. In the case of a dictionary the value used in the subscript is known as a key.

Using a subscript is just a slightly more convenient way to access information. In the code above I used airplanes[1] to access "Airbus 320", but I could also have written a function that allowed the same access by, say, getAnAirplane(1).

Usually, you can put data directly into arrays or dictionaries and access it with subscripts. But there are situations in which it is desirable to create your own custom subscripts, which is easy to do.

I've tried to make up an example that makes some sense that just uses a single subscript so it is simple.

Suppose we are very interested in everyone's Top Ten Movies, and so we create a class called EveryonesTopTenMovies. Each instance of the class EveryonesTopTenMovies represents a person. We have a little bit of interest in who these people are, so we do have a class definition that looks like this that includes properties that store people's names and phone numbers:

class EveryonesTopTenMovies {

var name: String = ""

var phoneNumber: String = ""

var movies:[String] = []

}

We can create an instance of this class for a person and set their name and phone number as follows:

let johnsTopTenMovies = EveryonesTopTenMovies()

johnsTopTenMovies.name = "John Cooper"

johnsTopTenMovies.phoneNumber = "415 328-1876"

Now obviously we can set their movie choices by using the property movie, but the idea here is to use subscripts more directly. So we add the subscript code to our class definition:

class EveryonesTopTenMovies {

var name: String = ""

var phoneNumber: String = ""

var movies: [String] = []

init() {

for var i = 0; i < 11; i++ {

self.movies.append("No movie set for item \(i+1)")

}

}

subscript (index: Int) -> String {

get {

if(index < 1 || index > 11) {

return "No 0th or 11th ranked movie!"

}

else {

return movies[index-1]

}

}

set(newValue) {

if(index < 1 || index > 11) {

print("No 0th or 11th ranked movie!")

}

else {

movies[index-1] = newValue

// was nameOfMovie

}

}

}

}

Note that the subscript definition is very much like a function or method definition. The main differences are that it uses the keyword subscript rather than func, the fact that it does not have a name, and that it has code that gets executed as either a getter or a setter, depending upon how the subscript is used. But the subscript definition does have input parameters with the same formatting rules as a function, and it has a return arrow and a type for the return value.

Another way to look at a subscript is that it works very much like a computed property.

As before, we create a new instance of the class EveryonesTopTenMovies:

let johnsTopTenMovies = EveryonesTopTenMovies()

Store a name into it:

johnsTopTenMovies.name = "John Cooper"

And some movies:

johnsTopTenMovies[1] = "Batman"

johnsTopTenMovies[2] = "Erin Brockovitch"

As a result of our defining our own class with subscript access, we can be finicky about things. Here "Batman" is John Cooper’s No. 1 most favorite movie. And we used a 1, not a 0, to access it. It's John’s 1st most favorite movie, not his 0th!

print ("John's most favorite movie is\(johnsTopTenMovies[1])")

Custom subscripts can be used for structures and enumerations as well as classes.

A class (or structure or enumeration) can use operator overloading for subscripts in the same way that it does for operator overloading with a function.

Hands-On Exercises

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

For Chapter 24 exercises, go to

understandingswiftprogramming.com/24