Table of Contents
1 Introduction
In part 1 of this tutorial series on building out an iOS application using Swift, we didn’t write any of our own code just yet. Instead we achieved something extremely important: a fundamental understanding of how Swift affects our use of the Cocoa Touch frameworks.
Using the “TaskMe” application that we generated in Xcode 6, it’s time to start adding some real functionality.
2 What you need
We’re going to be building an iOS app in Swift throughout this series, but to do so, you’ll need three things.
- A Mac with either OS X Mavericks or the latest OS X Yosemite beta release.
- A working, installed copy of Xcode 6 Beta 4 or higher.
- A basic understanding of Swift, which you can get from our Swift Reference Guide.
- To have read part 1 of this series.
This Swift tutorial was written with beta 5 as the current release, and given how active the development is on Swift at the moment, you might read this before we’ve had a chance to update it. So if a code example isn’t working, double check the changes to the language since beta 5.
3 Our first feature
The first feature we want to add is just simply having the ability to add a new task to our task list. Once we’ve created this feature, we’ll be able to tap the “+” button, type in our task’s title and some notes if we like, and when we tap “Save”, we’ll be taken back to the list of tasks.
3.1 Setting up our Storyboard
Due to the Apple’s prerelease software NDA, I can’t show any screenshots, which is a shame for sections of the tutorial like this one where there is some visual aspect to the work. I trust that you’re a smart cookie though and can follow the written instructions with only a little bit of working things out.
For our ‘new task’ user interface, we’d like the user to tape a “+” button and have a new controller pop up modally. Open up Main.storyboard
and we’ll get started on this.
We’re actually going to use two controllers to achieve this, a UINavigationController
and a normal UIViewController
which will be embedded in the new UINavigationController
(we won’t be reusing the one already on screen, as that’s for the main workflow). So drag out a UINavigationController
and UIViewController
from the Object Library (located at the bottom right of Xcode 6) into the editor area.
Delete the table view controller that was created with the UINavigationController
, then hold down control
, click on the UINavigationController
, and drag across to the newly created UIViewController
. In the popup that appears, choose “root view controller” from underneath the “Relationship Segue” section of. This will embed the UIViewController
in the UINavigationController
so we can later add “Cancel” and “Save” buttons to it.
Next we need to set up the segue for navigating to the UINavigationController
and UIViewController
. Before we do that, though, go into the MasterViewController.swift
file and delete the following two lines from the viewDidLoad
method:
let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "showAddTaskController:")
self.navigationItem.rightBarButtonItem = addButton
With those deleted, you can also delete the insertNewObject:
method.
Back in your Main.storyboard
file, drag a Bar Button Item from the Object Library onto the right hand side of the MasterViewController
‘s navigation bar. Then, in the Attributes Inspector, change its Identifier to “Add.”
Now we need to set up our segue from the MasterViewController
to the new UINavigationController
. Hold control
and drag from the Bar Button Item you just created to the new UINavigationController
, and choose “present modally” from within the “Action Segue” section of the popup.
Select the new segue — it will look like a rectangle in a circle as part of an arrow between the MasterViewController
and the new UINavigationController
— and set the Identifier to “showAddTask” using the Attributes Inspector.
The last thing left to do is to set up our screen. From the Object Library, drag two Text Fields into the UIViewController
, positioning them as you see fit. You should try setting up the Auto Layout constraints by holding control
and dragging around both the Text Fields and the containing view.
With the first Text Field selected, we’re going to edit some settings in the Attributes Inspector. First, change the empty placeholder to say “Task Title,” and then change the font size to 24 points. You can do this through the font editor, which can be opened by clicking on the “T” icon next to the font.
So that we can play around with the height as well as the width, let’s change the Border Style to be the second one from the right. Now you can play with the height; I made my text field about 60 points tall, and I also change the Alignment to be centered.
Now, do the same for the second Text Field, except maybe give it a smaller font size — I made mine 16 points — and height, and make the placeholder text something like “Notes.” I also set the alignment for the notes field to be left instead of center.
Click on the navigation bar in the new UIViewController
, and set the title to be “Add Task” in the Attributes Inspector.
With all of this done, we now have our two fields and the controllers. Next we need to create our UIViewController
subclass for our new Add Task screen.
Before we continue though, try running the application to see that you can now open the new screen, though we can’t get back.
3.2 Creating the AddTaskViewController
From the “File” menu, select “New → File” or use the cmd + N
keyboard shortcut to start creating our new AddTaskViewController
file.
Making sure you’re in “iOS → Source,” select “Cocoa Touch Class” from the options and click “Next.” In the “Subclass of:” field, type or select “UIViewController,” then add “AddTask” to beginning of the name in the “Class:” field.
Leave “Also create XIB file” unchecked, and make sure “Swift” is selected for “Language,” then click “Next.” A file dialog will pop up; choose the location for the file (the default is likely where you want it to be) and click “Create.”
Before we start editing the file that just popped up, we need to remember to set this to be the class for the UIViewController
we created in our Storyboard. Open our Main.storyboard
up again, select the new UIViewController
we created in the previous section, and set the Class to be AddTaskViewController
in the Identity Inspector (the panel on the top left that looks like a small square and some lines).
Now, with the focus on the AddTaskViewController
in Interface Builder, open up the Assistant Editor (the tuxedo-looking icon in the toolbar) so that we can set up the outlets between the Storyboard and our code.
Hold control
and drag from each of the Text Fields to the top of the class definition for AddTaskViewController
, naming each titleField
and notesField
respectively. This should give you something that looks like this:
class AddTaskViewController: UIViewController {
@IBOutlet weak var titleField: UITextField!
@IBOutlet weak var notesField: UITextField!
override func viewDidLoad() {
If you’ve done any iOS development work using Objective-C before, this will look similar to what you used to see in the header files.
The @IBOutlet
is a declaration of the connection between the Storyboard file and your code. The reason it uses an implicitly unwrapped optional is so that the view controller can be initialized without this set, and then these can be set once the views are ready. It won’t effect us in most cases, like setting things up in viewDidLoad
or viewWillAppear:animated:
, as it will be set by then.
The weak
declaration for the variable is also to ensure there are no unnecessary references. Without this, the AddTaskViewController
would own the two UITextField
s, which means that when the view attempts to be released for whatever reason, it wouldn’t be allowed to because the controller is still hanging onto it’s subviews.
3.3 Cancelling task creation
The next step for us is to set up the “Cancel” button so that when we tap it, our task isn’t saved. Instead, we simply hide the task creation screen.
In the Main.storyboard
file, we’re going to drag out a new Bar Button Item from the Object Library, and place it into the left hand side of the navigation bar of our AddTaskViewController
‘s screen.
Select the Bar Button Item, then change the Identifier to “Cancel” in the Attributes Inspector.
It’s important to use these standard versions of UI elements for two reasons: future-proofing and accessibility. We could have quite easily just set the title to be “Cancel,” but if Apple changes “Cancel” to be, for instnace, an “X” in the future then our application will be ready for that.
Standard UI elements also have accessibility baked in, and have been thoroughly tested by the best of the best that Apple has.
Now we need to get this “Cancel” button all hooked up. To do that, we’re going to create a new “dismiss” segue.
From the File menu, create a new file, and from the dialog that comes up, select “iOS → Source → Cocoa Touch Class,” then click “Next.” Set “Subclass of:” to “UIStoryboardSegue” and set the “Class:” to be “DismissSegue.” Make sure “Swift” is selected from the “Language” dropdown.
We’ve need to do one tweak before we use this class from our Storyboard. It will currently let a “dismiss” segue appear in Interface Builder, but it will fail at runtime due to some weird behind-the-scenes naming stuff Swift does. To fix this, we need to explicitly define the Objective-C class name so the Storyboard can find the correct class.
You will need to change the class definition to look like this:
@objc(DismissSegue) class DismissSegue: UIStoryboardSegue {
The declaration at the beginning (@objc(DismissSegue)
) is to make this class accessible to the Storyboard. This might change over time, but for now it’s required and the application will crash without it.
Now to create a perform
method for our custom segue that will simply dismiss the controller.
override func perform() {
(sourceViewController.presentingViewController as UIViewController).dismissViewControllerAnimated(true, completion: nil)
}
To make the compiler happy, we need to declare that we are sure that the presentingViewController
is a UIViewController
, as for some reason it’s defined as AnyObject!
. From there we can simply dismiss our modal view using dismissViewControllerAnimated:completion
.
Now to connect the dots. In the Main.storyboard
file, hold control
and drag from the selected “Cancel” button, to the MasterViewController
. Select the “dismiss” option from the popup.
With all that done, we’re ready to go! Run the application to see our work in action, woohoo!
3.4 Saving our task
Time to actually create some real business value — saving a task — and to do that, we’ll need to have a “Save” button.
In your Main.storyboard
file, drag out another Bar Button Item from the Object Library, this time placing it on the right hand side of our AddTaskViewController
‘s navigation bar.
Make sure it’s selected, then in our Attributes Inspector, change it’s Identifier to “Save” (didn’t see that coming, did you?)
While we’re here in this file, let’s also clean up something else that has been bugging me. The users of our application don’t care that the list screen is the “Master” screen; to them it’s the “Tasks” screen. Double click where it says “Master” and change it to “Tasks.”
Now add a “dismiss” segue between the “Save” button and the MasterViewController
just like you did with the “Cancel” button.
If you run the application now, you should be able to dismiss the modal using either of the buttons, which is exactly what we’re looking for. However, we’d also like to have a task added to a list of tasks, and for our Table View to refresh so that it shows the new task.
We need some central place to put these tasks, and we need a good definition of what exactly a task is, so let’s put a hold on working on the “Save” feature for now, and create these parts.
4 Our core business objects
Modeling our core business objects separately from our user interface is extremely important. It makes them flexible to use, and portable if we were ever to make our application work across platforms — such as adding an iPad or OS X application, or whatever the next ingenious Apple creation ends up being.
We don’t need much. A simple Task
struct and a TaskStore
class should do us nicely.
4.1 Creating the Task struct
Create a new file (“File → New → File” or command + N
), but this time, instead of creating a “Cocoa Touch Class”, we simply need a plain-old “Swift File.”
Name the file “Task” (the “.swift” will be appended automatically) and then we want to create a new “Task” struct within the file:
struct Task {
let title: String
let notes: String
init(title: String, notes: String) {
self.title = title
self.notes = notes
}
}
You may be thinking, “there is no way to edit the Task!” That’s right; instead of making the struct mutable, we’re going to embrace the functional style Swift is aiming to push us towards, and create a nice immutable value object.
When we need to make changes to a task, we’ll simply delete the old one and replace it with the new one. It will seem from the users perspective that it was just edited, but we’re creating less mutable state for us to manage this way, making our lives as programmers easier.
4.2 Managing our TaskStore
Next we need another Swift file for our TaskStore
which we’ll set up to be a singleton so that we can access the one instance at all times, adding and “editing” tasks as much as we like.
Create a “Swift File” like we did for our “Task.swift” file, but call it “TaskStore” instead this time.
class TaskStore {
class var sharedInstance: TaskStore {
struct Static {
static let instance = TaskStore()
}
return Static.instance
}
var tasks: [Task] = []
func add(task: Task) {
tasks.append(task)
}
func replace(task: Task, atIndex index: Int) {
tasks[index] = task
}
func get(index: Int) -> Task {
return tasks[index]
}
}
The first few lines of the TaskStore
class create a way for us to use a singleton of our TaskStore
by accessing it with TaskStore.sharedInstance
.
We then have a few basic functions for us to add
, replace
, and get
tasks from our list.
At some point in the future we could replace this with a more suitable version of this TaskStore
class, likely which stores the tasks across launches, but this will do for now.
5 Finishing our first feature
We’re going to wrap up part 2 here with a challenge for you to finish off the “Save” feature. Don’t worry just yet about displaying the list of tasks, as we’ll be covering that in the next part. Simply attempt to get the tasks saved into the TaskStore
. You’ll be able to see my solution to this in part 3.
One hint: the trick will be to give the segue from the “Save” button a name, and use the prepareForSegue:sender
method.
I hope you’ve enjoyed this series so far, and seen what it’s like to do iOS application development with Swift and Xcode 6. In my opinion so far, though there are some oddities thanks to the language and tools not being complete yet, it’s a large improvement from the verbose and messy history of Objective-C.
The post Swift Tutorial: Building an iOS application – Part 2 appeared first on .