Programming Basics in Swift
Swift is an elegant language. It mixes the efficiency of a compiled language with the flexibility and modern features of many scripting languages.
This chapter introduces some of the more common concepts of Swift, such as properties and collection classes. It also shows how properties are used from within Xcode when dealing with user interface elements. This sounds like a lot to accomplish, but Swift, the Foundation framework, and the Xcode tool provide a wealth of objects and methods and a way to build applications with ease.
Using let vs. var
If you have spent much time with Swift, you have seen the word var appear before variable declarations. You may also have seen let before other declarations. The word var is used to define a variable, while the word let is used to define a constant. This means that if you declare a value with let, you will not be able to change the value. The following code defines a constant:
let myName = "Brad"
Once you define a constant, you cannot change the value.
Caution Xcode 7 will now warn you if you declare a variable and never change its value. It will recommend using let instead of var.
myName = "John"
This will give you an error. It you want to create a mutable or changeable variable, you need to use var. For example, you can do the following:
var myName = "Brad"
myName = "John"
This will not give you any errors because myName is now a variable. This does not relate to only Strings and Ints, but it can also be used with collections and other more complex objects.
Variables give you more flexibility, so why would anyone ever want to use a constant? The quick answer is performance. If you know that you have a value that will not change, the compiler can optimize that value as a constant.
Understanding Collections
Understanding collections is a fundamental part of learning Swift. In fact, collection objects are fundamental constructs of nearly every modern object-oriented language library (sometimes they are referred to as containers). Simply put, a collection is a type of class that can hold and manage other objects. The whole purpose of a collection is that it provides a common way to store and retrieve objects efficiently.
There are several types of collections. While they all fulfill the same purpose of being able to hold other objects, they differ mostly in the way objects are retrieved. The most common collections used in Swift are the array and the dictionary.
Both of these collections can be created as constants or regular variables. If you create a collection as a constant, you must fill it with the objects at the time of creation. It cannot be modified after that point.
Using Arrays
The Array class is like any other collection, in that it allows the programmer to manage a group of objects. An array is an ordered collection, which means that objects are entered in an array in a certain order and retrieved in the same order.
Note There are some methods for working with arrays that allow you to change the order of the objects or to add an object at a specific location in the array.
The Array class allows an object to be retrieved by its index in the array. An index is the numeric position that an object would occupy in the array. For example, if there are three elements in the array, the objects can be referenced with an index from 0 to 2. Like with most things in Swift and other programming languages, an index starts at 0, not 1. See Listing 8-1.
As you can see, objects in the array can be retrieved via the index. The index starts at 0 and can’t exceed the size of the array minus 1. You can easily calculate the size of the array by sending a count message to the Array object, as shown here:
var entries = myArray.count
In fact, every collection type, in other words, Array and Dictionary, will respond to the count message.
Adding items to the end of an array is simple. You can just call the append method on the array. See Listing 8-2.
Swift provides you with many different methods for adding items to an array. If you want to add multiple objects to an array, you can use the standard += (often called plus equals) operator. Listing 8-3 creates an array and then adds three more String objects to the array on line 2. Notice the new values are in brackets instead of parentheses.
As discussed earlier, an array is actually ordered. The order of the objects in your array is important. There may be times where you need to add an item at a certain position in the array. You can accomplish this with the insert(atIndex:) method, as shown in Listing 8-4.
The array now contains One, Two, Three.
Accessing items in an array is simple. You can use standard square brackets to access an object at a certain position. For example, myArray[0] would give you the first object in the array. If you want to loop through each of the items in the array, you can use something called fast enumeration. Listing 8-5 is an example of fast enumeration.
The magic happens in line 2 of Listing 8-5. You tell Swift to assign each value of myArray to a new variable called myString. You can then do whatever you want to do with myString. In this case, you just print it. It will go through all of the objects in the array without you having to know the total number of objects. This is a fast and effective way to pull items out of an array.
Removing objects from an array is simple too. You can use the removeAtIndex method, as shown in Listing 8-6.
The output from Listing 8-6 will be One, Three. This is because you removed the object with the index of 1. Remember, this is the second object in the array because array indexes always begin at 0.
You have seen how flexible Swift is in letting you interact with arrays. They are powerful collections that you will use on a regular basis as a programmer. This section covered the basics of arrays, but there are many more things arrays can do.
Using the Dictionary Class
The Swift Dictionary class is also a useful type of collection class. It allows the storage of objects, just like the Array class, but Dictionary is different in that it allows a key to be associated with the entry. For example, you could create a dictionary that stores a list of attributes about someone such as a firstName, lastName, and so on. Instead of accessing the attributes with an index like with an array, the dictionary could use a String like "firstName". However, all keys must be unique—that is, "firstName" cannot exist more than once. Depending on your program, finding unique names is normally not a problem.
Here’s an example of how you create a dictionary:
var person: [String: String] = ["firstName": "John", "lastName": "Doe"]
This creates a simple dictionary called person. The next part of the declaration tells the dictionary what kinds of objects the keys and the values will be. In this case, the keys are Strings, and the values are Strings. You then add two keys to the dictionary. The first key is firstName, and that key has a value of John. The second key is lastName, and that has a value of Doe. You can access the values in the dictionary by using a similar notation to arrays.
print(person["firstName"])
This code will print the name Optional("John") since that is the value for the key firstName. The Optional appears in the previous example because the value of a key in a dictionary is an optional value. You can use the same style of code to change the values in a dictionary. Let’s say, for this example, that John now likes to go by Joe instead. You can change the value in the dictionary with a simple line of code.
person["firstName"] = "Joe"
You can add a new key to a dictionary with the same notation.
person["gender"] = "Male"
If you decide you want to remove a key from a dictionary, such as the gender key you just added, you can do so by setting the key to nil.
person["gender"] = nil
Now the dictionary will contain only firstName and lastName. Remember that dictionaries are not ordered. You cannot rely on the order, but there will be times when you need to iterate over a dictionary. This is done in a manner similar to arrays. The main difference is that in an array, you assign one variable, while in a dictionary, you need to assign the key and the value. See Listing 8-7.
This example will print the following:
firstName: John
lastName: Doe
Dictionaries are a great way to organize data that does not need to be ordered. It is also a great way to look up data based on a certain key. They are very flexible in Swift and should be used to organize and optimize your code.
Creating the BookStore Application
You are going to create an app that will demonstrate how to use arrays. You will create a UITableView and use an array to populate the UITableView with data. Let’s start by creating the base application project. Open Xcode and select a new Master-Detail Application project, as shown in Figure 8-1. In this project, you will create a few simple objects for what is to become your bookstore application: a Book object and the BookStore object. You’ll visit instance variables again and see how to get and set the value of one during this project. Lastly, you’ll put the bookstore objects to use, and you’ll learn how to make use of objects once you’ve created them.
Figure 8-1. Creating the initial project based on the Master-Detail Application template
Note This type of app would be a good candidate for using Core Data, but Core Data is not introduced until Chapter 11. You will use an array for data storage in this app.
Figure 8-2. Selecting the product (application) name and options
Figure 8-3. The source listing of the boilerplate project
Figure 8-4. Creating a new Swift file
Figure 8-5. The empty Swift file
Creating Your Class
You will notice that Xcode does not give you a new class when you create a Swift file. In Objective-C, Xcode used to create the .h and .m files for you. Swift is more flexible, and it is not necessary to have only one class per file. Xcode allows you to add the classes as you want.
Note It is still a good idea to keep your Swift classes in separate files. This makes organizing and finding classes easier, especially when you’re dealing with large projects.
Let’s create the Book class. Type the following code into the Book.swift file:
class Book {
}
Now you have your class, as shown in Figure 8-6. That is all you need to do to create a class.
Figure 8-6. The empty Book class
Introducing Properties
The class is simply called Book. True, you have a class, but it doesn’t store anything at this point. For this class to be useful, it needs to be able to hold some information, which is done with properties. When an object is used, it has to be instantiated. Once the object is instantiated, it has access to its properties. These variables are available to the object as long as the object stays in scope. As you know from Chapter 7, scope defines the context in which an object exists. In some cases, an object’s scope may be the life of the program. In other cases, the scope might be just a function or method. It all depends on where the object is declared and how it’s used. Scope will be discussed more later. For now, let’s add some properties to the Book class to make it more useful.
Listing 8-8 shows the same Book object from before, but now there are three new properties placed inside the brackets, on lines 11 to 13. These are all String objects, which means they can hold text information for the Book object. So, the Book object now has a place to store title, author, and description information.
Accessing Variables
Now that you have some properties, how can you use them? How are they accessed?. Unfortunately, simply declaring a property doesn’t necessarily give you access to it. There are two ways to access these variables.
If you are writing the code for a method within the Book object, accessing its property is quite simple. For example, you could simply write the following:
title = "Test Title"
From outside the object, you can still access the title variable. This is done through the use of dot notation.
myBookObject.title = "Test Title"
Finishing the BookStore Program
With the understanding of properties, you are going to now venture forth to create the actual bookstore program. The idea is simple enough—create a class called BookStore that will be stocked with a few Book objects.
Creating the View
Let’s start by first getting the view ready. If you need a refresher on how to build an interface in Xcode, refer to Chapter 6.
Figure 8-7. Preparing the Bookstore’s Detail View
@IBOutlet weak var detailDescriptionLabel: UILabel!
self.configureView()
// Update the user interface for the detail item.
if let detail: AnyObject = self.detailItem {
if let label = self.detailDescriptionLabel {
label.text = detail.valueForKey("timeStamp")!.description
}
}
Your DetailViewController.swift file should now look like Figure 8-8.
Figure 8-8. Modified DetailViewController
Figure 8-9. Adding some Label objects
Adding Properties
Next, you’ll add some properties to the DetailViewController class. These properties will correspond to the Detail View’s Label objects.
Figure 8-10. Creating variables
Figure 8-11. Naming the new variable
Adding a Description
Now you need to add the description to the view. The description is a little different in that it can span multiple lines. For this, you’re going to use the Text View object.
Figure 8-12. Adding a new Label object for the description
Figure 8-13. Adding a Text View to the Detail View
Note By default, the Text View control is filled with all kinds of seemingly random text. This text is called Lorem Ipsum text. If you ever need to fill up a page with text, you can find any number of Lorem Ipsum generators on the Web. As for the Text View control, the text can stay as it is since you’ll remove it during runtime. Plus, if it’s cleared, it becomes a little more difficult spotting exactly where the Text View control is on the screen—it’s white on white!
Caution As mentioned, it’s important to make the descriptionTextView property a UITextView type. If, for example, it were accidentally made a UILabel object, when trying to connect the Text View from the screen to the outlet, Xcode wouldn’t be able to find the descriptionTextView outlet. Why? Xcode knows that the control is a UITextView and is looking for an outlet that is of type UITextView.
Creating a Simple Data Model Class
For the application to work, it needs to have some data to display. To do this, you’re going to use the BookStore object you created earlier as the data model class. There’s nothing different about a data model class except that its whole purpose is to allow an application to access data via an object.
Modify the BookStore.swift file to look like Listing 8-11.
On line 12, you add a variable that will hold the list of books; the property is simply named theBookStore. Note that theBookStore is an array, which will allow you to add a series of objects, in this case, a set of Book objects.
Next, let’s add the code to the Swift file, BookStore.swift, as shown in Listing 8-12.
In Listing 8-12, lines 14 to 27 define the init method of the object, which is called whenever the object is first initialized. In this method, you initialize the two books you plan to add to your bookstore. Line 15 is where the first Book object is allocated and initialized. Lines 16 to 18 add a title, author, and description to your first book. Finally, line 19 adds the new Book object to the theBookStore array. The important thing to note here is that once the object is added to the array, the code can forget about it; the array now owns that object. Because of this, line 21 is not a problem.
Line 21 allocates a new Book object overwriting the old value. This tells the compiler that you’re no longer interested in using the old value.
Lines 22 to 26 simply initialize and add the second book to the array.
That’s it! That’s all you need to define a simple data model class. Next, you need to modify MasterViewController to access this class so that it can start displaying some data.
Modifying MasterViewController
The simple application has two view controllers: the main view controller, which is called MasterViewController, and a secondary one called DetailViewController. View controllers are objects that simply control the behavior of a view. For the application to start displaying data from the data model, you need to first modify MasterViewController—this is where the navigation of the application begins. The following code is already in place in the template that Xcode has provided. You’re just going to modify it to add your data model.
First you’ll need to modify the MasterViewController.swift file. You need to add a variable to hold the Bookstore object. Listing 8-13 shows that the instance variable is added as a property on line 15.
Now that the BookStore object is initialized, you need to tell MasterViewController how to display the list of books—not the detail, just the book titles. To do this, you’ll need to modify a few methods. Fortunately, Xcode has provided a nice template, so the modifications are small.
MasterViewController is a subclass of what’s called a UITableViewController class, which displays rows of data to the screen. In this case, these are rows of book titles (well, just two for this simple program but a list nonetheless).
There are three main methods that control what and how data is displayed in a UITableViewController.
Listing 8-14 details the changes you need to make to get the list of books displaying on the view. The changes start on line 63 in the source file.
Out of all of this code, you need to modify only a few lines. Everything else can stay the way it is. This is one of the advantages of using the Xcode templates. Line 68 simply returned 1; you needed to change it so that it now returns the count of items in the BookStore class.
Line 73 looks a little more complicated. Basically, each line of the UITableView is what is called a cell (a UITableViewCell to be specific). Line 73 sets the text of the cell to the title of a book. Let’s look at that code a little more specifically:
cell.textLabel!.text = myBookStore.theBookStore[indexPath.row].title
First, myBookStore is the BookStore object, which is pretty clear. You’re referencing the array in the BookStore object called theBookStore. Since theBookStore is an array, you can access the book you want in brackets in the indexPath.row. The value indexPath.row specifies which row you’re interested in—indexPath.row will always be less than the total count minus 1. So, calling myBookStore.theBookStore[indexPath.row] returns a Book object. The last part, .title, accesses the title property from the returned Book object. The following code is equivalent to what you just did in one line:
1 var book: Book
2 book = myBookStore.theBookStore[indexPath.row]
3 cell.textLabel!.text = book.title
Now, you should be able to build and run the application and see the two books you created in the data model, as shown in Figure 8-14.
Figure 8-14. Running the application for the first time
But, you’re not done yet. You need to make the application display the book when you click one of them. To make this happen, you need to make one last modification to MasterViewController.
The method tableView(_:didSelectRowAtIndexPath:) is called whenever a row is touched on the screen. Listing 8-15 shows the small changes you need to make in order to hook the Detail View to the book data.
If line 49 looks similar to line 73 in Listing 8-14, that’s because it’s basically the same thing. Based on indexPath.row, you select the specific book from the BookStore object and save it in a variable called selectedBook.
On line 51, you take selectedBook and store it in a property called detailItem that is already part of the existing DetailViewController class. That’s all you need to do in MasterViewController. You’ve basically passed off the book to DetailViewController. You’re almost done. Now you need to make a few small modifications to the DetailViewController so that it displays the Book object properly.
Modifying the DetailViewController
Earlier in this chapter, you modified the DetailViewController so that it would display some detail information about a book. In the code you just finished, you modified the MasterViewController so that it passes the selected book to the DetailViewController. Now all that remains is to simply move the information from the Book object in the DetailViewController to the appropriate fields on the screen. All of this is done in one method—configureView—as seen in Listing 8-16.
The configureView method is one of many convenience methods included in the Xcode template and is called whenever the DetailViewController is being initialized. This is where you will move your selected Book object’s information to the fields in the view.
Lines 27 to 29 in the DetailViewController.swift file is where you move the information from the Book object to the view. If you recall, line 51 in Listing 8-15 set the selected book into a property on the DetailViewController called detailItem. Lines 25 to 26 pull that item out into a Book object called myBook.
Lines 36 to 38 simply move each of the Book object’s properties to the view controls you built earlier in the chapter. That’s all you need to do in this class. If you build and run the project and click one of the books, you should see something like Figure 8-15.
Figure 8-15. Viewing the book details for the first time
Summary
You’ve reached the end of this chapter! Here is a summary of the topics covered:
Exercises
For a tougher challenge: