Getting Started series by Nick Schneider
Want to make iPhone apps? Don't know where to start? This series is perfect for you. In these short walk-throughs you'll understand the basics in manageable chunks. When you are done, you will have a working app!
The Motivation
Ever find yourself annoyed by a simple task that you doing over and over again? I recently started working on speed reading and I am in the need of tracking my Words Per Minute (WPM). Every time I sat down to read or working on reading exercises, I needed a timer and a spreadsheet to track my progress. This tracking meant sitting in front of my computer and all the distractions that come with it. Needless to say, I was having trouble staying focused.
To solve those issues, we'll build an app from the ground up that will calculate our reading rate, store our progress, and handle the timers. Maybe you'll learn how to double or triple your reading speed along the way.
Start Up Xcode
If you haven't installed or yet, watch the Mac Setup video to configure your computer
Create a New Project
Let's make a new project. Go to File > New > Project, and then make sure you select Single View Application from the iOS > Application tab, and then click Next. The new screen is where we name our project and fill in basic app information. Call it ReadingRates, put your name in the Organization Name field, and put com.YourName in the Company Identifier Field (make sure this match your Apple Developer ID if you plan to use a real device). Make sure iPhone is selected for Devices. Once your screen looks similar to below, click Next to move on.
The next screen will ask you where you want to save your project. You can use the default folder or navigate to a custom folder. Once you are ready, click Create. You will see that a good amount work has already been done for you. You can actually click Run (the play button in the top left corner or Command+R) and have a working app in the iOS Simulator.
Design the User Interface
Our goal for today is to make a calculator for finding our reading rate. The way we accomplish this is to have the user enter the average Words Per Line, the number of Lines Read, and the Time In Minutes spent reading. This means we need we need UI elements to display and input the information.
Let's head over to the Main.storyboard file by clicking on it in the left pane. Note: If the any of the navigators are missing, you can open them back up by clicking on the View and Editor buttons in the top right. You should see a blank view waiting for new buttons and text fields. First, we want to add a view to the background. We will use this in future project to add some life to how the app looks. Scroll through the Objects Palette in the bottom right until you find the View object.
Now we want to drag the View onto the blank canvas blueprint. We drag it to the center so that it fills the full view. Next, grab a Text Field and place it on the view. As you are moving it around, notice how recommended spacings will popup as blue lines, use these to you advantage when designing your layout. With the Text Field selected, go to the Attributes Inspector on the right pane and change a few settings.
- Alignment: Center
- Clear Button: Appears while editing
- Keyboard: Numbers and Punctuation (Since we want numbers)
Now we can use a little trick. Hold down the Option key while you left-click and drag the Text Field within Xcode's Interface Builder. Notice that it is making a copy of the object you are moving. The copy will have all of the custom attributes, saving you time and clicks! Make a total of three Text Field so that you have something that looks like this:
You can Build and Run right now to see that these fields work! This would also be a good time to play around with some of the other attributes such as keyboard type just to see what they do.
Now that we have our input Text Fields, we need to let our user know what to do with them. Create three Labels and name them:
- Words Per Line
- Lines Read
- Time In Minutes
Line them up using the guides so that they are centered and right justified next to the your Text Fields. Know that "Time In Minutes" is the longest, and so you should resize your text fields to line up with this label length. We need three more UI objects before we connect it all to code so it actually does something. Go ahead and add a Button and name it "Calculate", and lastly, grab two more Labels and call them "Words Per Minute" and "0". These will tell you app to calculate the words per minute and then display the answer, respectively. When all is said and done, you should have something like the following:
Connecting UI Elements to Code
Now we pull up the Assistant Editor by clicking on the middle button above Editor. If you have a smaller screen, feel free to close some of the other views. You will see that the Assistant Editor shows the Interface Builder along side the code file (ViewController.h or ViewController.m). This makes it simple to connect your UI to code.
Starting with the words per line Text Field, hold down the Control button and click and drag (or right-click) to the ViewController.h file below the @Interface line and above the @end line. (Use the top bread crumbs if you're in the ViewController.m to switch back to ViewController.h). You will see a popup asking for the connection details and the name. Here we want an Outlet for our UITextField with a weak Storage reference. Give the first Text Field the name wordsPerMinuteTextField . Note the use of camel case and the very descriptive name. You will want to get use to using conventions like these, as it makes it much easier to read your code (and for others to read your code).
The Calculate button is a little bit different, as this time we want the Connection to be an "Action" with Type "id", Event "Touch Up Inside", and Argument "Sender". These are the defaults when you select "Action" as your Connection type. Give this a descriptive name as well, by calling it calculateButtonPressed.
When all is said and done, your ViewController.h file should read as follows:
#import
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITextField *wordsPerLineTextField;
@property (weak, nonatomic) IBOutlet UITextField *linesReadTextField;
@property (weak, nonatomic) IBOutlet UITextField *timeInMinutesTextField;
@property (weak, nonatomic) IBOutlet UILabel *wordsPerMinuteLabel;
- (IBAction)calculateButtonPressed:(id)sender;
@end
Implementing The Calculator
Everything is all set and connected to code, so now we will actually make our app do some work. We will now implement the calculator by opening up ViewController.m, and add a new function above the @end line.
- (void)calculateWordsPerMinute {
float wordsPerLine = [self.wordsPerLineTextField.text floatValue];
float linesRead = [self.linesReadTextField.text floatValue];
float timeInMinutes = [self.timeInMinutesTextField.text floatValue];
float wordsPerMinute = wordsPerLine * linesRead / timeInMinutes ;
self.wordsPerMinuteLabel.text = [NSString stringWithFormat:@"%.0f", wordsPerMinute];
}
The first three lines grab the user input values from the Text Fields and store them in aptly named variables. Notice that we call the floatValue method to protect against non-numeric inputs. Next we cast a wordsPerMinute variable as a float and do the calculation. The last step is to set the text of the "Words Per Minute" Label to be a whole number from the double result. We use the token %.0f to display a whole number for aesthetics. We write this as a separate function so we can exploit the reusability later on.
Now we need to call this function whenever the calculate button is pressed, so we modify the IBAction code generated by adding the following line (the function was pre-generated for us when we connected the button to code).
- (IBAction)calculateButtonPressed:(id)sender {
[self calculateWordsPerMinute];
}
Build and Run your project to see what how it works. After playing for a bit, you will probably notice a few annoying aspects of our app. First, the keyboard never disappears, and second, the calculator displays "nan" for 0 over 0 and "inf" for non-zero over 0. The first issue being very important as we have to our users their screen back, and the second being more of an aesthetics issue.
Dismissing the Keyboard
There are a few ways to dismiss the keyboard and control the behavior when you have multiple Text Fields. Here we will take a simple approach that hides the keyboard whenever an acton we define is called. In this case when you hit the calculate button.
Add the following function to you ViewController.m file:
- (void)dismissKeyboard {
[self.view endEditing:NO];
}
Very simply, all this code does is tell the view we are done editing and then the view will find and "resign the first responder" for us. All this means it that we are saying we are done with input, go back to the normal view. Call this from the calculateButtonPressed function which should now look like this:
- (IBAction)calculateButtonPressed:(id)sender {
[self calculateWordsPerMinute];
[self dismissKeyboard];
}
Fixing "nan" and "inf" Displays
We can use a simple if-else statement to check if our denominator is non-zero. If it is zero, then we will just leave the text as initially defined. This is achieved by modifying the last line of the calculateWordsPerMinute function.
- (void) calculateWordsPerMinute {
float wordsPerLine = [self.wordsPerLineTextField.text floatValue];
float linesRead = [self.linesReadTextField.text floatValue];
float timeInMinutes = [self.timeInMinutesTextField.text floatValue];
float wordsPerMinute = wordsPerLine * linesRead / timeInMinutes ;
if (timeInMinutes) {
self.wordsPerMinuteLabel.text = [NSString stringWithFormat:@"%.0f", wordsPerMinute];
} else {
self.wordsPerMinuteLabel.text = @"0";
}
}
All we are doing here is asking if timeInMinutes is non-zero. If it is not, we update the WPM with the new value. If it is zero, we go back to the text "0". Since we do not have to format any input variables in the else, we use the short hand so we do not have to write as much code.
Build and run the project to play with you new app now behaving as we hoped!
A Little bit Extra - Dismiss Keyboard with Background Tap
We can add a nice little extra pretty easily. It is always a nice feature when you can tap on the background and have the keyboard be dismissed. To do this, we need to add gesture recognition to the view. Modify the viewDidLoad function to accomplish this desired functionality.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UITapGestureRecognizer *backgroundTap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:backgroundTap];
}
By utilizing the built in UITapGestureRecognizer, we tell our view to call dismissKeyboard every time we tap the background. Nice and easy, right?
And You Made an App! What's Next?
Thank you for following our walk-through! We hope you found it helpful in getting started.
Part 2 in our series will show you how to add UIAlertViews to your projects (popup messages), and then we will implement a stop watch to track our reading time.
Download the Xcode Project Files
Share with us your struggles, successes, and stories!