Homework 1 - PhraseThrow

In this assignment, you will be reimplementing the
PhraseThrow demo from class. Remember that PhraseThrow is a
very simple version of the popular party game Catch
Phrase. This is the only homework assignment that will
provide a step-by-side tutorial on how to complete it. This
assignment should take you no longer than an hour to complete,
and will be due on Tuesday, January 20 at 11:59pm.

Requirements

You will need a list of nouns! You can download that
list here:
nounlist.txt. You'll probably want to right click and
select Save Link As../... and then drag it into your
Xcode project.

The PhraseThrow demo

Open up Xcode. You'll be greeted with this
window:

We'll be starting from scratch today, so select Create a
new Xcode project. You'll be greeted with the Xcode editor
window, and a little pop up asking you to choose a template for
your new project. On the left hand side bar, you should select
iOS > Application (since that's what we're making)
and then choose Single View Application, like
so:

Then, you get to specify some options for your project.
Under Product Name: you should put PhraseThrow,
and under Organization Name:, just put your full name.
The rest you should fill out as follows:

It's not important what those fields mean, but you can
probably figure out what they all mean from the context.
Product Name is the name of your project, and Organization Name
is the name of../...well, your organization (say if you were
Google or something, but the name of the developer is also
traditional here). Organization Identifier is a unique
identifier for your developer organization, which is something
we'll talk about later in the semester, and Bundle Identifier
is a unique identifier for your project (also something we'll
cover later in the semester).

Then, you pick a directory to save your project in (don't
worry about the 'Create Git repository' stuff, unless you like
Git), and hit Create! Voila!

Now what?

So this may seem like an information overload to you guys.
So many tabs and features and buttons all over the place. Xcode
is a mess. This guide will help you pick the things you need to
know, though. The first thing we need to do is figure out what
app we're making!

Though, I'm not going to explain the game rules here. You
can look up the game that PhraseThrow is based off of, Catch
Phrase. The only difference is that our app will provide
the random nouns!

So, as a TL;DR, we're making an app which has a button that,
when pressed, picks a random noun from a (large) list of nouns
and displays it on the screen. This is more-or-less the minimum
our app will accomplish.

Now, let's start building our app. Look at the left sidebar
of Xcode:

Those are all the files in your project. They were all
autogenerated when you picked the template for your project
(remember, Single View Application). The main stuff that you
need to know right now is already out in the open:
AppDelegate, ViewController, and
Main.storyboard.

The AppDelegate isn't very important for this app. It
contains code that deals with app startup, backgrounding, and
shutdown operations. We don't want to modify any of it here for
this project, so we'll leave it alone (though we will mess
around with it in the future).

The ViewController is the class that../...well,
controls the main view. It's the C in MVC for this app.
It's in charge with processing everything for your app,
basically. We'll be working with it very closely in this
demo.

And finally, Main.storyboard. It's not a Swift file,
like the other two classes.s This is a Storyboard, which
is an abstraction for a view on an iPhone--it basically
represents what you see on your iPhone when people use
your app.

Creating the View

So, let's start with the Storyboard. Click on
Main.storyboard, and you'll be greeted with the Interface
Builder:

Whoops, that doesn't look like am iPhone screen. Apple is
making a push for arbitrarily sized iPhone development, so what
you're seeing is a generic size class--we'll get into all of
that in the next lecture though, so don't worry about it.

We're not interested in designing for arbitrarily sized
iPhones in this lecture. Therefore, on the right hand side, you
should see click the button you'll see the option:

Turn that off. A little popup should appear. Make sure that
"Keep size class data for" is set to iPhone, and click
Disable Size Classes.

Now it should look a little bit more like an iPhone screen!
Specifically, this screen is for an iPhone 5/5S. Great, so now
we can start building our app's main screen.

The first thing we want is a title label; we want the word
PhraseThrow in big letters across the top of our screen,
so that everyone knows what our app is called. On the right
hand side of your screen, you should see the Object
Library, which looks like this:

Scroll down until you see an option for Label. Then,
drag and drop it onto your view! It's as simple as that. You
should see, if you move the label around the iPhone view, that
Interface Builder will give you guidelines on how to center
your label on the screen and whatnot. Make sure your label is
centered horizontally, like so:

A label is just an object that displays text. That's
all--nothing more! But the text inside can be modified--so,
let's do that to get our title label. Double click on the label
to edit its text, and edit it to "PhraseThrow" (without
the quotes). Then, on the top right hand side of your screen,
you should see a little toolbar like this:

That is the Inspector Toolbar--you'll want to select the
fourth one from the left. That is the Attributes
Inspector. It's full of information about your label (if
not, click on your label to get it into focus, and then you
should see tons of info). Use the Attributes Inspector to make
your PhraseThrow title label nice and big and pretty (note that
this will probably involve resizing your label). Mine looks
like this now:

Great! Hopefully your label looks like awesome--if not, it's
totally cool if you didn't modify the label at all. Now, we'll
need two more things for our view: a label to display the
random word on the screen, and a button to say "Hey, get a
random word." You can find a button in the Object Library, just
like your label. So, you should set up your screen like
this:

It's good to have good design. Keep your button close to the
bottom, and keep your labels grouped together near the top.

Making the Connections

Okay, so we have this view with two labels and a button, but
right now if your app were to run, it would do nothing. Why?
The labels and button are not connected to any code or logic.
They do nothing. So, now we're going to start working with
code. In the top right hand corner, you'll want to click on
this icon (on non-Yosemite machines,
you'll see a bow-and-tie guy). This is the Assistant editor and will
help you make connections in your code. You should now have a screen looking
like this:

So, we'll want to make two connections in our code: one for
the nextWordLabel so that we can update it with a word, and one
for the Next Word! button so we know when to update the
nextWordLabel. To make a connection, simple hold the
Control button on your keyboard and click and drag from
the Label to your code, like so:

Release, and you'll get a little pop up asking you to fill
in some information about the label. You should fill it out
with something reasonable like this:

Then, click Connect. We won't worry about what most of this
stuff means, because you're probably at an information
overload. But all you need to know is that the label's name in
your code is nextWordLabel, and its type is a
UILabel. You should see that a line of coded was added
to your ViewController:

@IBOutlet var nextWordLabel : UILabel!

We'll explain what that trailing exclamation mark means down below;
for now, don't worry about it. Now, we'll do the same thing with the button,
except we'll fill out its connection features a little differently. Make
sure under Connection you select Action and not Outlet
(otherwise your button won't do anything). Then, name it, and
make sure its type is UIButton (it's something else, by
default). Then, under Event, make sure you select Touch Up
Inside. It shoud look like this:

Now, you should see that an entire Swift function was added
to your code:

@IBAction func nextWordButton(sender : UIButton) {
}

The code in this function is called each time the button is
pressed.

Now, we have connected the View to your ViewController
class; we're officially done working with Interface Builder,
for now.

Writing the Code

Don't continue into this section unless you're familiar with
Model-View-Controller (MVC). If you're unfamiliar with MVC, go
back to the lecture on read about it. Also if you haven't read
the Swift intro in Lecture 1, do that now!

First, we should make a model. We'll make a class called
NounDictionary, which will basically just hold a massive list of
nouns. This class will also support one function: randomWord(), which
may return a random noun from the list. Think carefully about how this fits
into Model-View-Controller.

We'll first need a list of nouns to save in our NounDictionary class.
Make sure you download nounlist.txt
(right click, Save Link As../...) and drag and drop it into
your Xcode project. You should drag it into the Supporting
Files folder. A dialog should popup whe you do this. Just
select Copy items if needed and click Finish.

Next, we need to make a new class file. Hit Cmd+N, or go to File > New >
File. You'll see a prompt like this:

Select Cocoa Touch Class, since this is basically a template for
new iOS templates. You'll see another form like this:

Under Class, put NounDictionary, and under Subclass of:, just
leave it as NSObject. Leave everything else (make sure Language is
set to Swift). Hit Next, and then hit Create. You'll be
all set with a new empty class that looks like this:

import UIKit
class NounDictionary: NSObject {
}

Now, we can implement this class. In the interest of time, I'll just post
the annotated code for the NounDictionary class:

So, now, let's focus only on our ViewController code. Let's
leave Assistant editor mode (click the button to the left of
the suit and tie guy) and open up ViewController.swift. Right
now, the only stuff you should have in there is this body of
code:

There are two functions in there that you didn't write:
viewDidLoad, which is a function that is called when
your iPhone loads up your Main.storyboard, and
didReceiveMemoryWarning, which we will never worry
about in this class.

We want to focus on viewDidLoad. This is where we
will initialize everything. You can start by writing to
nextWordLabel, just to get our feet wet with our app. Change
your viewDidLoad method so that it looks like
this:

Now you will run your app for the first time. In the top
left hand corner of Xcode is a little icon. Click it and watch your app
run on the Simulator.

Uh-oh. You might want to dive into Interface Builder later
to fix nextWordLabel to make sure the Label is big
enough to hold the entirety of its contents. But more
importantly, where did our button go?!

The interface you built was for an iPhone 5. The simulator
by default runs an iPhone 4S. Therefore, your button is getting
cut off! Stop the simulation (by hitting the Stop button next
to the Play button) and access the drop down menu right next to
it to select an iPhone 5:

Now, run the simulation again and everything should be
good:

Alternatively, you could just move the button up the screen
on Interface Builder so that it displays on both iPhone 4S and
iPhone 5. Later on in the course, we'll talk about how to do
this programmatically so you don't ever have to worry about
this.

Now, we know how to edit nextWordLabel, and we have
our app displaying as it should. We've also written a class called
NounDictionary which will give us random nouns. So, now we need to mash
these two amenities together. Our ViewController will have an instance
of NounDictionary. Every time our button is pressed, we'll make a call to
NounDictionary to grab a random word, and then we'll update our label.
Sounds easy enough?

We won't implement an init for our ViewController--it only appears once,
so we can do our initialization in the viewDidLoad method. Set up
a member variable for our ViewController's NounDictionary like this:

What does that ! mean at the end of NounDictionary?
Well, it has to do with optionals. Basically, nounDict is a
NounDictionary? optional type, which means it can be a
NounDictionary or nil. But, when we use the ! at
the end of the type, it basically says always unwrap this optional.
So, every time you use self.nounDict, it will implicitly unwrap
the optional for you. This is convenient at times, but you need to be careful
to not use self.nounDict when it might be nil.

So, to solve this problem, one of the first things we will do is make an
instance of it. That way, we know it's not nil for the rest of the
lifetime of the app. (It's also worth noting that the Swift language won't
let us instantiate the NounDictionary at the same time that we
declare it, which is why we have to instantiate it separately.) So, our
viewDidLoad method should look like this:

Hand-In

I know how to use Git!

Put your PhraseThrow implementation in the hw/hw1/ directory and commit
and push it. Make sure you push by the deadline, because that's when I'm
running my pull script. Also, make sure you push everything. You should
commit/push your PhraseThrow folder (which contains three things: another
folder called PhraseThrow, a folder called PhraseThrowTests, and a file
called PhraseThrow.xcodeproj). If you need a refresher, check out the
Git guide written by
Sally!

I don't know how to use Git!

We are using Git this semester to manage your assignments and grades.
Git is a revision control system--it's a safe way to manage code in
repositories, especially with multiple users. The cluster Macs already have
Git (probably), and most of you guys (probably) already have Git installed
on your Macs, but it'd be smart to update to the latest version of Git
from here. Once you do that,
open up your Terminal (Applications -> Utilities -> Terminal). In your
Terminal, type

git --version

and hit enter. You should see something like:

git version 2.1.3.36.g8e36a6d

Might not be exact, but as long as you don't see something like "Command
not found", you're good. Next, you'll want to clone your repository.
This means making a copy of it on your machine. To clone your repository,
type the following command:

Where, instead of ANDREWID, you would put your own Andrew ID.
This command will ssh into AFS to grab your repository. This command works
if you're working on the cluster Macs. You will need to input your password,
however, since you are ssh'ing into AFS.

When you perform this command, you should have a folder now (likely
in your Home folder, but where you performed the git clone command) with
your andrew ID. This is your repo. Inside this folder, you should
see a README, a folder called 'grades', and a folder called 'hw'). Make
sure you find this directory.

This will download any new information to your repo. You should, in
general, do this before you intend to add any new work to your repo.

To hand in (for now, though this is total assault on the entire point of
Git), drag your PhraseThrow folder (which should contain three things:
another folder called PhraseThrow, a folder called PhraseThrowTests,
and a file called PhraseThrow.xcodeproj) and drop it in the hw/hw1/
directory in your repository.

Then, go back to your Terminal and type:

git status

This presents a status about what files you have in your repository. You
should hopefully see something like this:

On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
PhraseThrow/
nothing added to commit but untracked files present (use "git add" to track)

Type:

git add PhraseThrow/

You just staged your PhraseThrow folder--basically, this says "I'm
planning on committing this folder to my repository." Then, you need to
actually commit the folder to your repository--this is equivalent to
permanently saving the folder to your repository. To do this, type:

git commit -m "Submitting HW1"

This saves everything that you staged to your repository permanently. It
then attaches a little message to your commit which just explains the files
that you committed to your repository, "Submitting HW1". Finally, you will
have to upload your changes to AFS (so that I can see them)! Simply type

git push

And this uploads your changes. Then, you're done! Now, go read Sally's
guide on how to use Git
to cement this new technology in your head.