My First iOS App

Now that you’ve gained some familiarity with the Swift programming language, we’ll take you step-by-step through the process of creating a simple, real-world iOS app.

You’ll need a Mac computer (OS X 10.10 or later), running the latest version of Xcode, which includes all features needed to design, develop, and debug an app. Xcode also contains the iOS SDK, which extends Xcode to include the tools, compilers, and frameworks necessary for iOS development.

contentImage

To download the latest version of Xcode:
Go to https://developer.apple.com/xcode/downloads/.
On the page, click the download link for the latest prerelease version of Xcode.
Enter your Apple ID and password when prompted.
The Xcode .dmg is downloaded into your /Downloads directory.
Double-click the .dmg and follow the installation instructions.

Create a New Project

To create a new project:
Open Xcode from the /Applications directory, and you’ll see the Xcode welcome window.

contentImage

In the welcome window, click “Create a new Xcode project” (or choose File > New > Project).
Xcode displays template choices in a new window.
In the iOS section at the top of the dialog, click Single View App under the Application section and then click Next.

contentImage

Project Options

In the dialog that appears, choose additional options for your project.

contentImage

Organization Identifier: If you don’t have an organization identifier, use com.example
Click Next.In the dialog that appears, select a location for saving your project, then click Create

Get Familiar with Xcode

Take a few moments to familiarize yourself with the main sections of the Xcode workspace:

contentImage

You’ll use the areas identified in the window throughout the lessons. Don’t be overwhelmed; each area is described in more detail when it’s time to use it.

Run Simulator

Xcode contains an app called Simulator, for use in building and running your app. Simulator provides an idea of how your app would look and behave if it were running on a device.
Simulator has the capability of modeling a number of different types of hardware: iPad, iPhones with varying screen sizes, and so on.
Choose your desired device from the Scheme pop-up menu; in this case, make sure that you select the iPhone 6 Simulator, not an iOS Device.

contentImage

Click the Run button, located in the top-left corner of the Xcode toolbar:

contentImage

Alternatively, choose Product > Run (or press Command-R).
When running an app for the first time, Xcode will ask whether you’d like to enable developer mode on your Mac.

contentImage

Xcode displays messages about the build process in the activity viewer, which is in the middle of the toolbar.

Running your App

After Xcode finishes building your project, Simulator starts automatically.
Before the app finishes launching, you’ll briefly see a launch screen with your app’s name, MyApp.

contentImage

Then, you should see something like this:

contentImage

Right now, the Single View Application template doesn’t do much; it just displays a white screen.
You have just created and launched your first iOS app!You can quit Simulator by choosing Simulator > Quit Simulator or by pressing Command-Q.

Review the Code

The project navigator displays all of the files in your project. If the project navigator isn’t open, click the button on the far left end of the navigator selector bar.

contentImage

If necessary, open the MyApp folder in the project navigator by clicking the disclosure triangle next to it.
Select AppDelegate.swift.
Xcode opens the source file in the window’s main editor area.Alternatively, double-click the AppDelegate.swift file to open the app in a separate window.

The App Delegate Source File

The AppDelegate.swift source file has two primary functions.
1. Creating a point of entry and a run loop that delivers input events to your app. This work is carried out by the UIApplicationMain attribute (@UIApplicationMain), which appears toward the top of the file.
2. Defining the AppDelegate class, which serves as the blueprint for the app delegate object. The app delegate creates the window where your app’s content is drawn, and provides a place to respond to state transitions within the app. The AppDelegate class is where you write your custom app-level code. It contains a single property, window.var window: UIWindow?SWIFTThe AppDelegate class also contains templates of important methods. These predefined methods allow the application object to talk to the app delegate.func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplicationLaunchOptionsKey: Any]?) -> Bool

func applicationWillResignActive(_ application: UIApplication)

func applicationDidEnterBackground(_ application: UIApplication)

func applicationWillEnterForeground(_ application: UIApplication)

func applicationDidBecomeActive(_ application: UIApplication)

func applicationWillTerminate(_ application: UIApplication)SWIFTDuring an app state transition – for example, app launch, transitioning to the background, and app termination – the application object calls the corresponding method in the app delegate, giving it an opportunity to respond appropriately.A method templates can also be used to add custom code that will execute when the methods are called.

The View Controller Source File

Select ViewController.swift in the project navigator to view it.

contentImage

At this point, your ViewController.swift code should look something like this:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view…
}
}

Become familiar with the source files. Later on, you’ll be writing code into this source code file.

Open Your Storyboard

storyboard is a visual representation of the app’s user interface, showing screens of content and the transitions between them. You see exactly what you’re building while you’re building it.

In the project navigator, select Main.storyboard.
Xcode opens the storyboard in Interface Builder, which is the visual interface editor, located in the editor area. The storyboard’s background is called the canvas. The canvas is used to add and arrange UI elements.

Your storyboard should look similar to this:contentImage
At this point, your app’s storyboard contains one scene that represents an app screen showing content. The left-pointing arrow on the canvas is the storyboard entry point, which means that this scene loads first upon starting the app.The scene on the canvas doesn’t share the iPhone 6 screen’s exact dimensions, because it’s a generalized representation of your interface. It can be applied to any device, in any orientation.

Build the Basic UI

Xcode provides a library of objects that can be added to a storyboard file.
The elements in the UI are called views, and they display content to the user.
All view objects in iOS are of type UIView, or one of its subclasses.
Let’s add a text field to our view.
Open the Object library. It appears at the bottom of the utility area on the right side of Xcode.contentImageType text field in the filter field in the Object library to quickly find the Text Field object.
Drag a Text Field object from the Object library to your scene:contentImageIf necessary, click the text field to reveal the resize handles, which appear as small white squares on the element’s borders. Drag the resize handles to resize the UI element.contentImageBlue layout guides appear to help you place, resize and position the text field.

Placeholder Text

Use the text field’s placeholder text to prompt the user to enter the value you need.
Select the text field, and open the Attributes inspector in the utility area, in order to edit the properties of an object in your storyboard.

contentImage

Enter the placeholder text and press Return to display it in the text field.
You can also edit the attributes of the system keyboard that’s displayed when a user selects the text field.
Make sure the text field is still selected.
In the Attributes inspector, find the field labeled Return Key and select Done.
This change will make the default Return key on the keyboard more pronounced to the user by changing it into a Done key. There are many different attributes available for each view. Just go through the list in the Attribute inspector, and you will find many useful options and customizations.

Label and Button

We have added a label (Name) and a button (Submit) to our scene from the Object library:

contentImage

A label just displays static text in the UI, while a button is interactive. The user can tap the button to trigger an action that you’ve defined. In the next lesson, you’ll create an action for the button.You can edit the text of label and/or button by double-clicking.The outline view, which appears on the left side of the canvas, shows you a hierarchical representation of your storyboard objects. You should be able to see the text field, label, and button you just added listed in the hierarchy.

contentImage

Not only do views display themselves onscreen and react to user input, they can serve as containers for other views. Views are arranged in a hierarchical structure called the view hierarchy.

Adopt Auto Layout

Auto Layout is a powerful layout engine that makes it easy to design adaptive layouts. Describe your intent as you position a scene’s elements, and let the layout engine determine how that intent is best implemented.
Intent is described using constraints, which are rules explaining where one element should be located in relation to another, what size it should be, or which of two elements should shrink first when the space available for each is somehow reduced.
stack view provides a streamlined interface for laying out a collection of views in either a column or a row.
You can easily wrap your existing interface in a stack view, adding the necessary constraints to make it display properly under different circumstances.

While pressing the Shift key on your keyboard, select the text field, label, and button.
On the bottom right of the canvas, click the Stack button.

contentImage

Xcode wraps the UI elements in a stack view, stacking them together.

contentImage

Xcode analyzes your existing layout to figure out whether the items should stack vertically or horizontally. You can change the settings from the Attribute inspector.

Stack View

To set or change the stack’s settings, open the outline view and select the Stack View object.

contentImage

In the Attributes inspector, type 12 in the Spacing field. Press Return. You can also change the Axis of the Stack.
Notice that the UI elements space out vertically, and the stack view grows along with them.

contentImage

You can play around with the settings and check results on the canvas.
Let’s also change the Alignment to Leading, so that the elements position left.

Constraints

On the bottom right of the canvas, open the Pin menu.

contentImage

Above “Spacing to nearest neighbor“, click the two horizontal constraints and the top vertical constraint to select them. They become red when they are selected.
These constraints indicate spacing to the nearest leading, trailing, and top neighbors. In this context, the term nearest neighbor means the boundary of the closest UI element.
Type 0 in the left and right boxes, and type 60 in the box at the top.
In the pop-up menu, next to Update Frames, select Items of New Constraints.
The Pin menu should look something like this:

contentImage

In the Pin menu, click the Add 3 Constraints button.

The scene UI should now look something like this:

contentImage

Using the same Pin menu, you can make the text field stretch the entire width. Select the text field, open the Pin menu, add the two horizontal constraints, and enter 0 for each. Clicking the Add 2 Constraints button will make the text field stretch.

Run Your App!

Run your app in Simulator:contentImageClick inside of the text field, and type some text, using the keyboard. You can toggle the software keyboard by pressing Command-K. If you rotate the device (Command-Left Arrow or Command-Right Arrow) or run the app on a different device, the text field adapts to fit the appropriate size, depending on the device’s orientation and screen size.
If you experience issues, reset or clear the constraints by clicking the Resolve Auto Layout button to reset or clear the constraints.contentImage

Now, we can add functionality to the interface!

View Controllers

Elements in a storyboard are linked to source code. It’s important to understand the relationship between storyboard and code.

In a storyboard, a scene represents one screen of content and, typically, one view controller. A view controller implements the app’s behavior, managing a single content view with its hierarchy of subviews.
Xcode has already created one, ViewController.swift, which was connected to the scene you’re currently working on in your storyboard. In the future, as you add more scenes, you’ll make this connection yourself in the Identity inspector. The Identity inspector lets you edit properties of an object in your storyboard, in relation to that object’s identity, such as the object’s class.

contentImage

At runtime, your storyboard will create an instance of ViewController, your custom view controller subclass. The app screen will show the UI defined in this scene in your storyboard and any behavior defined in ViewController.swift.The scene is connected to ViewController.swift, but there are other connections to be made, as well. To define interaction in your app, your view controller source code needs to be able to communicate with your storyboard views. This is accomplished by defining additional connections – called outlets and actions – that go between the views in the storyboard and the view controller source code files.

Creating Outlets

Outlets offer a way to reference the interface objects that you added to your storyboard from source code files. For example, you’ll need to create outlets for the text field and label them in your UI to be able to reference them.

To connect the text field to the ViewController.swift code, open your storyboard, called Main.storyboard.
Click the Assistant button in the Xcode toolbar near the top right corner of Xcode to open the assistant editor.

contentImage

ViewController.swift displays in the editor on the right.
In your storyboard, select the text field. While holding the Control button, drag from the text field on your canvas to the code display in the editor on the right, stopping the drag at the line below the class definition.

contentImage

A dialog appears. For Name, type the desired name for your text field. In our example, we’ve named it nameTextField.

contentImage

Click Connect.

Xcode adds code to ViewController.swift that will store a pointer to the text field and configures the storyboard to set up that connection:@IBOutlet weak var nameTextField: UITextField!SWIFTThe weak keyword means that it’s possible for that property to have no value (to be nil) at some point in its life. The rest of the declaration declares a variable of type UITextField named nameTextField.

Repeat the process for the label, and name it nameLabel. You now have a way to refer to the interface elements from code. Now, you’ll need to define a user-initiated event that triggers interaction between those elements.

Define an Action to Perform

An action is a piece of code that is linked to an event that can take place at some point in your app. When that event takes place, the code is executed. An action method can be declared to accomplish anything from manipulating a piece of data to updating the UI.
An action is created in the same way as an outlet. That is, control-drag from a particular object in your storyboard to a view controller file.
Let’s create an action for our button, to set the label’s text to the text the user inputs in the text field.

Control-drag from the Submit button on your canvas to the code display in the editor on the right.
In the dialog that appears, for Connection, select Action.
For Name, type a name, for example: setLabelText.
For Type, select UIButton.
Your dialog should look like this:contentImageClick Connect.The Type field value defaults to AnyObject, a type used in Swift to describe an object that can belong to any class.Xcode adds the necessary code to ViewController.swift to set up the action method.@IBAction func setLabelText(_ sender: UIButton) {

}SWIFTThe sender parameter points to the object responsible for triggering the action – in this case, a button. The rest of the declaration declares a method named setLabelTextThe IBAction attribute indicates that the method is an action to which you can connect from your storyboard in Interface Builder.

Defining an Action

In the method implementation, add this line of code:nameLabel.text = nameTextField.textSWIFTThe above code sets the label’s text property to the text field’s text property.We refer to the label and text field by the names we defined while creating the corresponding outlets.

Now, run your app on the Simulator, type a name in the text field and press the Submit button. The typed name should appear as the Label.

contentImage

Congratulations! You’ve created your first action!

View Controller Lifecycle

So far, our app has a single scene, whose UI is managed by a single view controller. As you build apps that are more and more complex, you’ll be dealing with greater numbers of scenes. You will need to have the ability to manage loading and unloading views as they’re moved on and off the screen.
An object of the UIViewController class, and of its subclasses, comes with a set of methods that serve to manage its view hierarchy. iOS automatically calls the methods at appropriate times when a view controller transitions between states.contentImageviewDidLoad(): Called when the view controller’s content view is created and loaded from a storyboard.
viewWillAppear(): Intended for any operations that you want always to occur before the view becomes visible.
viewDidAppear(): Intended for any operations that you want to occur as soon as the view becomes visible, such as fetching data or showing an animation. A complementary set of teardown methods exists, as shown in the state transition diagram above.

Creating a ToDo List App

Now that you’ve become familiar with the basic concepts involved in creating iOS apps, let’s create a real-world ToDo List App. In the app, there will be a list of to-do items, which can be removed and edited. New items can also be added to the list.
We have modified our scene from the previous lessons, so that it has the following UI, which represents the add/edit page for a ToDo item:contentImageWe have just changed the stack’s alignment, renamed the label and button, changed the placeholder for the text field, and removed the action from the button.You can see and modify the connections (outlets and actions) by selecting the UI element in the storyboard and going to the Connection Inspector window.Now it’s time to create the scene that shows the entire list of to-do items. We’ll use table view (UITableView), a powerful built-in iOS class that is specifically designed to create and display a scrolling item list.
First, open Main.storyboard.
Next, go to the Utility area to open the Object library. Drag a Table View Controller object from the list and drop it on the canvas to the left of the existing scene.
You now have two scenes, one for displaying the list and one for adding a new item. If nothing happens when dragging a table view with content to the canvas, you are most likely attempting to drag a table view. Make sure that you select a table view controller when dragging, rather than a table view.

Create the Opening Scene

When the app is launched the list should be the first thing your users see. We need to set the table view controller as your first scene in Xcode.
Drag the storyboard entry point from the opening scene to the table view controller.contentImageWith the table view controller set as the initial view controller in your storyboard, this will be the first scene that loads upon launching the app.contentImageWhen you run your app, you’ll see an empty table view, which is a screen with a number of horizontal dividers separating it into rows that contain no content.

Modifying the Table View

In the outline view, find and select Table View, which is nested under Table View Controller Scene > Table View Controller:contentImage
With the table view selected, go to the Utility area and open the Size inspectorcontentImage
In the Size inspector, type 90 in the Row Height field. Press Return.

Now, run your app. The row height has increased.contentImageNow we need to add custom classes for our table view cells and table view controller, in order to control them and be able to add outlets.

Custom Table Cells

The individual rows in a table view are managed by table view cells. The single cell shown in the table view controller scene in your storyboard acts as a prototype for the other cells in the table view, so any design and/or behavior assigned to this cell will display in all of the others.
In our list, a simple label for each table view cell will display the ToDo item’s name.
To do this find a Label object in the Object library and drag it onto the table cell. Place the Label object close to the left side of the table cell, aligned to the center of the cell. Also, stretch it to the end of the cell.

contentImage

Choose File > New > File. A dialog appears. To its top, and under iOS, select Cocoa Touch Class under the Source section and click Next.

contentImage

In the Class field, type the name of our items’ cell, which is Item.
Select UITableViewCell in the “Subclass of” field. The name of the class will change to ItemTableViewCell.
Make sure that the Language option is set to Swift

contentImage

Click Next.
The save location defaults to your project directory. Leaving the defaults as they are, click Create.
Xcode creates a file that defines the ItemTableViewCell class as ItemTableViewCell.swiftThis creates a class for our cells, inherited from the UITableViewCell class. We can now configure the items in our table.

Configuring a Custom Cell

To connect the table view cell in the scene to our just-created custom cell subclass, select the Table View Cell in the storyboard’s outline view.

contentImage

With the table view cell selected, open the Attributes inspector in the Utility area.
In the Attributes inspector, find the field labeled Identifier and type ItemTableViewCell.

contentImage

Open the Identity inspector. In the field labeled Class, select ItemTableViewCell.

contentImage

The class of our cell prototype is now set to the newly created ItemTableViewCell class

Connect the Table Cell UI to Code

Before we can display dynamic data in your table view cells, we need to create outlet connections.
In your storyboard, select the label in the table view cell.
Click the Assistant button in the Xcode toolbar to open the assistant editor.

contentImage

From the label on your canvas, control-drag to the code display in the editor on the right, to ItemTableViewCell.swift. In the dialog, give your label the Name of nameLabel. Click Connect.
The property will be generated for the label:

@IBOutlet weak var nameLabel: UILabel!

Even though you added all the necessary UI elements to your table view cells, they’re showing up empty, until you implement the data model behind it.

Define the Data Model

The data model stores the information to be displayed by the scene. To define it, define a simple class with the properties needed for the items. For our purposes, we need a name property of type String.
To create a new data model class, choose File > New > File
When the dialog appears, select Swift File under the Source section, and click Next.
In the Save As field, type Item as the name of your model.
Click Create, and Xcode creates a file called Item.swift.

Add the following code to create the class:

class Item {
var name: String

init(name: String) {
self.name = name
}
}

This newly defined class can now be used to add items to our table.

Drag and drop from the options below to create a data model for shopping items; with name and price properties.

class Item {

var name: String

var price: Double
init

(name: String, price: Double) {

self.name = name

self.price 

= price

}

}

Load Initial Data

At this point, we have a data model for an item, the Item class. We need to write some code to have real data display in the table’s cells.
The first step is to create a custom table view controller subclass to manage the items list scene.
Choose File > New > File, and then create a new Cocoa Touch Class named Item.
In the “Subclass of” field, select UITableViewController.
The class title now changes to ItemTableViewController.
Leave these defaults as they are, and click Create. Xcode creates ItemTableViewController.swift, a source code file that defines your custom table view controller subclass.

Next, open your storyboard to point the table view controller scene to ItemTableViewController.swift. Select the table view controller by clicking on its scene dock until the entire scene is outlined in blue. Then select the ItemTableViewController class from the Identity inspector.

contentImage

Select the ItemTableViewController class from the Identity inspector.

Load Initial Data

Open ItemTableViewController.swift
Add the following code just below the class line in ItemTableViewController.swift

var items = [Item]()

Declare a function to load the sample data into the array:

func loadSampleItems() {
items += [Item(name:”item1″), Item(name:”item2″), Item(name:”item3″)]
}

The function adds three sample Items to the array.
Now, add the method to the viewDidLoad():

override func viewDidLoad() {
super.viewDidLoad()

loadSampleItems()
}

Add the method to the viewDidLoad().

Display the Data

Methods for displaying data in the table are found in ItemTableViewController.swift. Find the data source method numberOfSections(). The template implementation looks like this:

override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}

Change the return value from 0 to 1, and remove the warning comment.

override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

This code has the table view show one section instead of zero.

The next data source method, tableView(), tells the table view how many rows to display in a given section. The number of rows should be the same as the number of Items objects in your items array:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}

The number of rows should be the same as the number of Items objects in your items array.

Display the Data

The last data source method is tableView(). It configures and provides a cell to display for a given row. Each row in a table view has one cell, which determines what content appears in that row, along with its layout.
In ItemTableViewController.swift, find and uncomment the tableView(_:cellForRowAtIndexPath:) data source method.
After you do that, the template implementation looks like this:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: “reuseIdentifier”, for: indexPath) as UITableViewCell
// Configure the cell…

return cell
}

The template performs several tasks. It asks the table view for a cell with a placeholder identifier, adds a comment about where code to configure the cell should go, and then returns the cell.
To make this code work for your app, you’ll need to change the placeholder identifier to the one you set earlier for the prototype cell in the storyboard (ItemTableViewCell), and then add code to configure the cell.
Your tableView(_:cellForRowAtIndexPath:) method should look like this:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: “ItemTableViewCell“, for: indexPath) as! ItemTableViewCell
// Configure the cell…
let item = items[indexPath.row]
cell.nameLabel.text = item.name
return cell
}

Notice that the cell type is changed to ItemTableViewCell. Then we take the corresponding item from our items variable and assign the cell’s label the name of the item.
indexPath is the number of the current row, which is used to query the item.

Now, when you run the app, you will see the items you added to the items array appear in the table:contentImageNote that there’s some overlap between the table view cells and the status bar; that will be fixed in the next lesson.

Navigation

The data display as expected; now we need to provide for navigation from the items list to the item scene. The transitions between app scenes are called segues.
navigation controller manages transitions backward and forward through a series of view controllers. The set of view controllers managed by a particular navigation controller is called its navigation stack.
Open Main.storyboard.
Select the table view controller by clicking on its scene dock.

contentImage

With the table view controller selected, choose Editor > Embed In > Navigation Controller.
Xcode now adds a new navigation controller to your storyboard, sets its storyboard entry point, and establishes a relationship between the new navigation controller and your existing table view controller.

contentImage

On the canvas, the icon that connects the controllers indicates the root view controller relationship.
You might notice that your table view now has a bar at the top. This is a navigation bar.

contentImage

Every controller on the navigation stack has its navigation bar, which can contain controls for backward and forward navigation.

Configure the Navigation Bar

To add a title, double-click the navigation bar in the items list scene or edit the Title property in Attributes inspector.

contentImage

Enter a title and press Return.
In the Object library, find a Bar Button Item object.
Drag a Bar Button Item object from the list to the far right of the navigation bar.
A button called Item appears where you dragged the bar button item.

contentImage

Select the bar button item and open the Attributes inspector, where you’ll choose Add from the pop-up menu next to the System Item option.
The button will change to an Add button (+).

contentImage

The varying choices for the System Item property can be used to change the appearance of the button.

Configuring Navigation

To have the Add button (+) bring up the item scene, we need to trigger a segue (or transition) to that scene.
On the canvas, select the Add button (+) and Control-drag from the button to the item scene.contentImage
A shortcut menu with the title Action Segue appears in the location where the drag ended.contentImage
The Action Segue menu allows you to choose what type of segue to use when transitioning.
Choose show from the Action Segue menu.
Run your app. You can click the Add button and navigate to the item scene from the items list scene. Because you’re using a navigation controller with a show segue, the backward navigation is handled for you, and a back button automatically appears in the scene.contentImage
We have also removed the Save Item button from the scene; we’ll add the Save and Cancel button to the navigation.You can change the transition by choosing the segue and modifying the Segue option in the Attributes inspector.
To identify the segue, type AddItem in the Identifier field in the Attributes inspector.

Configuring Navigation

To add the “New Item” scene to the navigation, simply repeat the steps you used for the items list scene when embedding it in a Navigation Controller. Give it a title and add two Bar Button Items, selecting Cancel and Save as the System Item in Attribute inspector.
Run the app. When you click the Add button from the items list, you should see this:

contentImage

The buttons haven’t been linked to any actions yet, so they need to be configured for actions.We’ve changed a few of the items on the view, so we need to update the layout of the stack view. In the “New Item” scene, select the stack view.
On the bottom right of the canvas, open the Resolve Auto Layout Issues menu.

contentImage

Under Selected Views, choose Update Constraints.The elements remain in their original positions, but the stack view is now pinned to the navigation bar, instead of to the top margin of the view.

Store New Items

Now we need to implement the Save functionality in our ViewController.
Open ViewController.swift and add an Item property:var item: Item?SWIFTThis is an optional Item, meaning that it may be nil at any point.

The Save button requires an outlet in order to work.
Open Assistant Editor, and control-drag from the Save button on your canvas to the code display in the editor on the right.
In the dialog that appears, type saveButton in the Name field and click Connect:

contentImage

Now, when a user presses the Save button, we need to display the items list with the new item added. An unwind segue moves backward through one or more segues to return the user to an existing instance of a view controller. Reverse navigation is accomplished by using an unwind segue.
Whenever a segue is triggered, you’re provided with a place to add your own code, which is then gets executed. This method is called prepare(for segue:).
Open ViewController.swift and add the following method:override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if sender as AnyObject? === saveButton {
let name = nameTextField.text ?? “”
item = Item(name: name)
}
}UNDEFINEDThis method determines whether the Save button has been tapped and then creates the appropriate item object.This code uses the identity operator (===) to check that the object referenced by the saveButton outlet is the same object instance as sender.
Notice the nil coalescing operator (??) in the name line. It is used to return the value of an optional if the optional has a value, or return a default value otherwise.

Store New Items

The next step in creating the unwind segue is to add an action method to the destination view controller.
In this method, you’ll write the logic to add the new item (that’s passed from ViewController, the source view controller) to the items list data and add a new row to the table view in the items list scene.
Open ItemTableViewController.swift and add the following method:

@IBAction func unwindToList(sender: UIStoryboardSegue) {
let srcViewCon = sender.source as? ViewController
let item = srcViewCon?.item
if (srcViewCon != nil && item?.name != “”) {
// Add a new item
let newIndexPath = IndexPath(row: items.count, section: 0)
items.append(item!)
tableView.insertRows(at: [newIndexPath], with: .bottom)
}
}

This code uses the optional type cast operator (as?) to try to downcast the segue’s source view controller to type ViewController.This adds the new item to the existing list of items in the data model. It also animates the addition of a new row to the table view for the cell containing information about the new item.

To trigger this action method, you need to create the actual unwind segue. To do this, first open your storyboard. Control-drag from the Save button to the Exit item at the top of the scene.

contentImage

Choose unwindToList: from the shortcut menu.
Now, when users tap the Save button, they navigate back to the items list scene, during which process the unwindToList(_:) action method is called.Run the app. Now, when you click the Add button (+), create a new item, and click Save, you should see the new item in your list.

Cancel

To implement the behavior of the Cancel button, select the Cancel button in your storyboard, then Control-drag from the Cancel button on your canvas to the code display in the editor on the right. In the dialog, select Action in the Connection field.
For Name, type cancel.
For Type, select UIBarButtonItem.
Your dialog should look like this:

contentImage

Click Connect.
In the cancel() action method, add the following line of code to dismiss the scene without storing any information:

@IBAction func cancel(sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}

Run your app. When you click the Add button (+) and click Cancel instead of Save, you should navigate back to the list without adding a new item.

Allow Editing

Next, give users the ability to edit an existing item. When the user taps on an item, the item scene will pop up with information that the user can edit and save.
Open your storyboard and select the table view cell.
Control-drag from the table view cell to the item scene.
Choose show from the Selection Segue menu.
Select the newly created segue and, in the Attributes inspector, type ShowDetail in the Identifier field. Press Return.

contentImage

Run the app. In the list scene, you should be able to tap a table view cell to navigate to the item scene. The content area in the scene is blank.

Allow Editing

There are now two segues to transition to the same scene, so you need to have a way to identify whether the user is adding a new item or editing an existing one.
You can differentiate the segues based on the identifiers you assigned to them earlier: AddItem and ShowDetail.
Open ItemTableViewController.swift.
Find and uncomment the prepare(for segue: ) method:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}

Edit the code as follows:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == “ShowDetail” {
let detailVC = segue.destination as! ViewController

// Get the cell that generated this segue.
if let selectedCell = sender as? ItemTableViewCell {
let indexPath = tableView.indexPath(for: selectedCell)!
let selectedItem = items[indexPath.row]
detailVC.item = selectedItem
}
}
else if segue.identifier == “AddItem” {

}
}

The code passes the value of the clicked cell to the ViewController.
Now, we need to update the ViewController for the item.
Open ViewController.swift and edit the viewDidLoad() method.

override func viewDidLoad() {
super.viewDidLoad()

if let item = item {
nameTextField.text = item.name
}


}

This code sets the name in ViewController to display data from the item property if it’s non-nil. This only happens when editing an existing item.Run your app. You should be able to click a table view cell and navigate to the item scene, which is prepopulated with data about the item. However, if you click Save instead of overwriting the existing item, the app adds a new item.

Allow Editing

We need to update the implementation of unwindToList() to add or replace items:
Modify the method:

@IBAction func unwindToList(sender: UIStoryboardSegue) {
let srcViewCon = sender.source as? ViewController
let item = srcViewCon?.item
if (srcViewCon != nil && item?.name != “”) {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
// Update an existing meal.
items[selectedIndexPath.row] = item!
tableView.reloadRows(at: [selectedIndexPath], with: .none)
}
else {
// Add a new meal.
let newIndexPath = NSIndexPath(row: items.count, section: 0)
items.append(item!)
tableView.insertRows(at: [newIndexPath as IndexPath], with: .bottom)
}
}
}
This code determines whether a row in the table view is selected. If it is, that means a user tapped one of the table view cells to edit an item. In other words, this if statement gets executed when an existing item is being edited.Run your app and ensure that the Save functionality is working properly, both for new and existing items.

Cancel

In order to work for the Edit mode, the Cancel button requires some additional modification. To do this, find the cancel() action method in ViewController.swift, and modify it to look like this:

@IBAction func cancel(sender: UIBarButtonItem) {
let isInAddMode = presentingViewController is UINavigationController

if isInAddMode {
dismiss(animated: true, completion: nil)
}
else {
navigationController!.popViewController(animated: true)
}
}

This creates a Boolean value that indicates whether the view controller presenting this scene is of type UINavigationController. As indicated by the constant name isInAddMode, this means that the Add button was used to present the scene. This is because the scene is embedded in its own navigation controller when presented in this manner, meaning that navigation controller presents it. Run the app to be sure that the Cancel button in Add and Edit modes is working as it should.

Support Deleting Items

To add an Edit button to the table view, find the viewDidLoad() method in ItemTableViewController.swift, and add the following code:

navigationItem.leftBarButtonItem = editButtonItem

Run the app, and notice that there’s an Edit button on the left of the table view’s navigation bar. Click the button, and the table view goes into editing mode:

contentImage

To actually delete an item, find and uncomment the tableView(_:commit editingStyle: forRowAt IndexPath:) method. The template implementation looks like this:

// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
}
}

In the if editingStyle = .delete condition add the following:

items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)

This removes the selected item from our items list.

Adding Images

To add images to your project, select Assets.xcassets in the project navigator to view the asset catalog.
The asset catalog stores and organizes your app image assets.
In the bottom left corner, click the plus (+) button and choose New Image Set from the pop-up menu.

contentImage

An image set represents a single image asset, but can contain different versions of the image, to display correctly at different screen resolutions. 2x is the display resolution for iPhone 6 Simulator.
Double-click the image set name and rename it.
On your computer, select the image you want to add. Drag and drop the image into the 2x slot in the image set.
We’re using the SoloLearn logo as the sample image.

contentImage

To display an image, add an Image View to your view from the Object library.

contentImage

To select an image to show, open your storyboard and select the image view.
With the image view selected, open the Attributes inspector in the utility area.
In the Attributes inspector, find the field labeled Image and select your asset name, in our case “logo”.

contentImage

As you can see, we have added the image to the New Item scene.

You can add assets to any of your scenes

Persist Data

Data persistence is one of the most important and common issues in iOS app development.
Currently, our data is reset every time we reopen the app, because we haven’t implemented data persistence.
To be able to encode and decode itself and its properties, the Item class needs to conform to to the NSCoding protocol. To conform to NSCoding, the Item needs to subclass NSObject.
In Item.swift, find the class line and adopt the protocol:

class Item: NSObject, NSCoding {

The NSCoding protocol declares two methods that any class that adopts to it must implement so that instances of that class can be encoded and decoded:

func encode(with aCoder: NSCoder)
init(coder aDecoder: NSCoder)

The encodeWithCoder() method prepares the class’s information to be archived, and the initializer unarchives the data when the class is created. You need to implement both the encode(_:) method and the initializer for the data to save and load properly. The encode() method should look like this:

func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: “name”)
}

Add the required initializer:

required convenience init?(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: “name”) as! String
self.init(name: name)
}

The question mark (?) means that this is a failable initializer, and it may return nil.
Because the other initializer you defined on the Item class, init?(name), is a designated initializer, its implementation needs to call to its superclass’s initializer – to do that, add super.init() to it:

init?(name: String) {
self.name = name
super.init()
}

The question mark (?) means that the initializer is failable, and it may return nil.

Saving Data

The next step is to create a persistent path on the file system, where data will be saved and loaded.

static let Dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = Dir.appendingPathComponent(“items”)

You mark these constants with the static keyword, which means they apply to the class instead of an instance of the class. Outside of the Item class, you’ll access the path using the syntax Item.ArchiveURL.
Now that you can save and load an individual item, you need to save and load the items list whenever a user adds, edits, or removes an item.
To implement the method to save the items list, in ItemTableViewController.swift add the following method:

func saveItems() {
let isSaved = NSKeyedArchiver.archiveRootObject(items, toFile: Item.ArchiveURL.path)
if !isSaved {
print(“Failed to save items…”)
}
}

This method attempts to archive the items array to a specific location, and returns true if successful.It uses the constant ArchiveURL, which was defined in the Item class to identify a location for saving the information.To save the items list when a user adds, removes, or edits an item, you need to call the saveItems() method in unwindToList() – after the else clause, but inside of the outer if statement, and in tableView(_:commitEditingStyle:forRowAtIndexPath:) – after the items.remove(at: indexPath.row) line.This code saves the items array whenever an item is deleted.

Loading Data

Now, implement a method to load saved items in ItemTableViewController.swift:

func loadItems() -> [Item]? {
return NSKeyedUnarchiver.unarchiveObject(
withFile: Item.ArchiveURL.path!) as? [Item]
}

This method attempts to unarchive the object stored at the path Item.ArchiveURL and to downcast that object to an array of Item objects.

To load the items list at the appropriate time, find the viewDidLoad() method in ItemTableViewController.swift, and modify it to:

override func viewDidLoad() {
super.viewDidLoad()

navigationItem.leftBarButtonItem = editButtonItem()

// Load saved items
if let savedItems = loadItems() {
items += savedItems
}


}

This will try to load the items from the file and add them to the items array.
Run your app, add a few new items, and quit the app. The newly added items will be there the next time you open the app.

contentImage

Congratulations! Now you have a functional ToDo List App.

Persist Data

Data persistence is one of the most important and common issues in iOS app development.
Currently, our data is reset every time we reopen the app, because we haven’t implemented data persistence.
To be able to encode and decode itself and its properties, the Item class needs to conform to to the NSCoding protocol. To conform to NSCoding, the Item needs to subclass NSObject.
In Item.swift, find the class line and adopt the protocol:

class Item: NSObject, NSCoding {

The NSCoding protocol declares two methods that any class that adopts to it must implement so that instances of that class can be encoded and decoded:

func encode(with aCoder: NSCoder)
init(coder aDecoder: NSCoder)

The encodeWithCoder() method prepares the class’s information to be archived, and the initializer unarchives the data when the class is created. You need to implement both the encode(_:) method and the initializer for the data to save and load properly. The encode() method should look like this:

func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: “name”)
}

Add the required initializer:

required convenience init?(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: “name”) as! String
self.init(name: name)
}

The question mark (?) means that this is a failable initializer, and it may return nil.
Because the other initializer you defined on the Item class, init?(name), is a designated initializer, its implementation needs to call to its superclass’s initializer – to do that, add super.init() to it:

init?(name: String) {
self.name = name
super.init()
}

The question mark (?) means that the initializer is failable, and it may return nil.

Saving Data

The next step is to create a persistent path on the file system, where data will be saved and loaded.static let Dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

static let ArchiveURL = Dir.appendingPathComponent(“items”)

You mark these constants with the static keyword, which means they apply to the class instead of an instance of the class. Outside of the Item class, you’ll access the path using the syntax Item.ArchiveURL.
Now that you can save and load an individual item, you need to save and load the items list whenever a user adds, edits, or removes an item.
To implement the method to save the items list, in ItemTableViewController.swift add the following method:

func saveItems() {
let isSaved = NSKeyedArchiver.archiveRootObject(items, toFile: Item.ArchiveURL.path)
if !isSaved {
print(“Failed to save items…”)
}
}

TThis method attempts to archive the items array to a specific location, and returns true if successful.It uses the constant ArchiveURL, which was defined in the Item class to identify a location for saving the information.To save the items list when a user adds, removes, or edits an item, you need to call the saveItems() method in unwindToList() – after the else clause, but inside of the outer if statement, and in tableView(_:commitEditingStyle:forRowAtIndexPath:) – after the items.remove(at: indexPath.row) line.This code saves the items array whenever an item is deleted.

Loading Data

Now, implement a method to load saved items in ItemTableViewController.swift:

func loadItems() -> [Item]? {
return NSKeyedUnarchiver.unarchiveObject(
withFile: Item.ArchiveURL.path!) as? [Item]
}

This method attempts to unarchive the object stored at the path Item.ArchiveURL and to downcast that object to an array of Item objects.

To load the items list at the appropriate time, find the viewDidLoad() method in ItemTableViewController.swift, and modify it to:

override func viewDidLoad() {
super.viewDidLoad()

navigationItem.leftBarButtonItem = editButtonItem()

// Load saved items
if let savedItems = loadItems() {
items += savedItems
}


}

This will try to load the items from the file and add them to the items array.
Run your app, add a few new items, and quit the app. The newly added items will be there the next time you open the app.

contentImage

Congratulations! Now you have a functional ToDo List App.

Leave a Comment