iOS for High School Students: Making Your First iOS App: Part 2/2

Mike Jaoudi By on February 1, 2013

This post is also available in: French, Polish

Learn how to make an iOS app.

This is a blog post by Tutorial Team member Mike Jaoudi, a Computer Science major at New York University. You can find Mike on Twitter and .

Welcome back to the iOS for High School Students: Making Your First iOS App Tutorial series!

In the first part of the series, you created a simple but fun game where you furiously tried to tap a button as fast as possible.

However, the app didn’t look all that good! In this tutorial, you’ll take that app and add some awesome-sauce to it :]

Specifically, you are going to learn how to add custom images and sounds to the game to give the player the sharp gaming experience they are used to from other iOS apps.

This tutorial will pick up where the last tutorial left off. If you don’t have it already, here’s the project you developed in the previous tutorial.!

Why Bother?! The Game is Done!

You may be thinking “Meh, why bother working on this anymore?! No new features are going to be added to the game. Why does the game need custom images and custom sound?! I have better things to do… like Xbox!”

Well, take a look at this next picture, and see if you still have the same impression:

Which app do you think someone would be more likely to buy? :]

The picture on the left is the end result of Part 1 — the image on the right is the result of adding custom graphics and sound. As you can see, the extra effort you’ll expend in this tutorial to extend your app will definitely be worth it – plus you’ll learn a lot along the way!

Adding custom images to your app will always give it a more polished and professional appearance. Remember, your app is competing with a million others; an app that is intuitive and pleasing to look at is almost as important as intuitive and pleasing code! :]

Double Density

To get started, download the resources for this project. Many thanks to Vicki Wenderlich for making these images!

After you download the file, unzip it and take a look at the images stored inside:

Notice how there are two copies of each image. The smaller image is used for devices with regular displays (older iPhones and iPads) and the other is scaled to double the height and width for Retina displays (the crisp display on newer iPhones and iPads).

The Retina display density is twice that of a non-Retina display, so a 20×20 image (with 400 pixels) needs a 40×40 image (1600 pixels) to take advantage of the high-quality Retina display. Newer iOS devices have Retina displays so it’s important to include these higher-resolution images.

What happens if you only include the normal resolution files, you ask? In that case, images in your app will look slightly blurry or blocky, as in the example below:

Handling multiple versions of graphics files must require extra coding, right? Nope! (Chuck Testa!) :]

Apple uses a special file naming convention where you just add “@2x” to the end of your file name before the extension. For example, if you have a file named image.png, the retina version would be named image@2x.png, as below:

Then when you’re writing code or using storyboards, just refer to the image name without the @2x added onto it. The app will figure out what kind of device it’s running on and automatically pick the retina version if it’s available! Pretty slick! :]

Getting Started

Start Xcode and open up the project from Part 1. Again if you don’t have it already, you can snag it here.

First, you’ll add all of the images and sounds to the project. To do this, select all of the items from the folder to where you downloaded them previously, and drag them into the area where all your files are in Xcode. It makes the most sense to put your graphical and sound resources in onto the Supporting Files group, as below:

Make sure that you check the box at the top that says Copy Items into Destination Group’s Folder, then click Finish.

By selecting the “Copy items” checkbox, Xcode will make a copy of all the images and store it in your project directory. This is important because it will make your project still work even if you delete the files from their original location where you downloaded them, or move that folder somewhere else. It’s a good practice to keep everything an Xcode project needs inside its directory.

Excellent! Now all of the sounds and images are in the project and ready to be used. Since you’re manipulating the new graphical elements of your project, it will make sense to work with them in your Storyboard layout! :]

Images that Tell a Story(board)

Below is your storyboard, just as you left it from Part 1 of this tutorial. The “Tap Me” button will be the first thing to get a makeover. Select the button and have a look at its Attributes in the right sidebar. Remember, the Attributes tab is the fourth from the left and looks like a little slider:

Find the State Config attribute for the button near the top of the list:

Buttons can have several different states in your application. There are four different states that your button can have: Default, Highlighted, Selected and Disabled.

  • Default – The button is not pressed
  • Highlighted – The button is pressed
  • Selected – The button has been switched on, but does not have to be pressed. Used for “toggle” switches for example.
  • Disabled – The button has been disabled and cannot be pressed

The ones you’ll use most often are Default and Highlighted – since they mean pressed and unpressed.

And indeed, the “Tap Me” button will have a different look for the Default and Highlighted states. Make sure the State Config is set to Default, and then set the Background attribute to button_tap_deselected.png. Remember, you are using the filename without the @2x added onto it!

Now take a look at your fancy new game button!

Uh…that looks terrible! The button has two overlapping titles! What’s going on here?!

Ah — the image AND the button both have text indicating the action. You need to turn off the button title. In the attributes for your image, delete the “Tap Me” text from the Title.

The button looks better -but the sizing is a little off. What should be a nice circular button is a little squished! :]

You could resize the button directly in the storyboard just by looking at it, but your design sense should be tingling at this point. Remember, you’re dealing with an image that has an exact size: 228 by 240 pixels, in this case. It makes sense to enter the exact size of the button right into the storyboard.

Make sure the button is still selected, and switch to the Size tab in the right sidebar. It is the second button from the right and it has a ruler icon:

Change the Width to 228 and the Height to 240.

Hey — the button image now looks great! Make sure to position the button on the storyboard to the center of the screen, and make sure it isn’t overlapping the other two labels on the screen.

Okay! Now that the size and positioning of the button is set, you still need to change what the button looks like when it’s pressed. To do that, you will use a different image to represent the depressed state.

Go back to the Attributes tab and set the State Config to Highlighted, as below:

Now set the Background to button_tap_selected.png

Great — it looks like your fancy new button is ready to go! :] Click the Run button in the upper left corner and see it in action:

Wonderful! Your app is starting to look a lot better with that one set of images added!

The rest of your app is looking a little dated in comparison, isn’t it? Time to give the rest of it a makeover! :]

Image Frenzy!

You’ve just learned how to add images as button background images — but what if you don’t need a button and just want the image? Image Views to the rescue! As the name suggests, an Image View is a view that can display images.

Awesome! Sounds like you can use an Image View to make your app look even better! Go into the object library and drag an image view into the storyboard, like so:

It would look nice if you had some borders at the top and bottom of the screen — a nice checkerboard pattern has been provided for you.

Drag an Image View into the main view. Place one at the top of the main view, and one along the bottom of the view. You’ll set the width and height more precisely in just a moment, so just roughly resize them to stretch across the width of the view and make them a little shorter, as pictured here:

Super! Now you need to set the image to be displayed in each of the two Image Views. Click on the top image view and go to the Attributes column. Set the Image to checker_top.png.

Now you’ll need to set the Image View to be the the correct size for your screen. Go to the Size tab. Set the Width to 320 and the Height to 22.

That looks a bit better! Now you just need to do the same thing to the bottom Image View.

Click on the bottom image view and go into the Attributes column. Then set the Image to checker_bottom.png, as shown:

Now set the bottom Image View to the proper size! Go to the Size tab, and set the Width to 320 and the Height to 22.

Time to check out how things look in the app! Hit the Run button in the upper left corner:

So far so good! Your app is starting to look better — but that awful green color in the background is a real bummer, now that you have your shiny new graphics in place!

Time to repaint the walls of your app! :]

Backgrounds, Revisited

In Part 1, you set the background color of the main view to green. While setting a background color is easy, there isn’t a real easy way to set a background image right on the storyboard. Time to leave the world of storyboards for a bit and return to the code!

Open up ViewController.m and have a look at the viewDidLoad method. Remember that this method is called right after all the views are created. It is also called before all of the views are displayed on the screen.

Hm…this sounds like the perfect place to set up your background image! :]

When you wanted to change the text displayed in a label, you had to set up outlets with the IBOutlet keyword. Now, you want to change the background of the view. Do you need to setup another outlet for the background image?

No — fortunately, the project automatically sets up an outlet for you, so you can go ahead and change the background color. Update your viewDidLoad method like this:

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
 
    self.view.backgroundColor = [UIColor purpleColor]; // ADD THIS!!
 
    [self setupGame];
}

Since this is a ViewController, self refers to the View Controller; the background view is view; finally, the view’s background color is backgroundColor.

Note: In code, you refer to color by way of the UIColor class. Colors are typically stored as separate red, green and blue (RGB) values, since any color can be those three basic colors in various combinations. Rather than mix and match color values, UIColor has some built-in shortcuts such as purpleColor that you’re using here, just to make your life easy! Wasn’t that nice of them? :]

Run your app! You should now see a nice purple background as below:

Wow.

Well, the good news is you now know how to set the background color from code.

The bad news? That purple looks horrible! I didn’t think it could possibly get worse than that neon green ;]

UIColor has one more trick up its sleeve: aside from solid colors, it can take any image and convert it to a pattern that you can use in the background! If the image is smaller than the background, it will repeat or tile the image so it covers the entire view.

Perhaps that feature can save you from this purple haze? :]

Change the code for the background color in viewDidLoad to the following:

  self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bg_tile.png"]];

Rather than a specific color like green or purple, you’re calling colorWithPatternImage to get a pattern from an image. Images are stored as UIImage objects, so here you are setting up an UIImage with the “bg_tile.png” image, which will be the background for the app.

Run your app now — does it look any better?

Aww yeah — that looks a whole lot better! If you don’t see the nice background image, make sure the file name is spelled correctly in the code you changed above.

There are two more background images available for you to use in your app: one is for the timer label, and the other is for the score label.

Add these two lines to the viewDidLoad method, just after the line you added above which sets the view’s background:

  scoreLabel.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"field_score.png"]];
  timerLabel.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"field_time.png"]];

The pattern is set in exactly the same manner, except the views use different images.

That’s it! Now run your project:

Whoa! This is problematic. The text was a little hard to read before — but now it is practically impossible to read!

If the background image is smaller than the view, UIColor will try to help you out by tiling, or repeating, the image; however, if the background image is too large, it will be cut off.

Just as you set the “Tap Me” button size right in the storyboard, you can do the same for the two labels. Open up MainStoryboard.storyboard and select the timer label. In the Size tab of the Utilities sidebar, set the Width to 133 and set the Height to 46, as such:

Now do the same thing for the score label. Select the score label, set the Width to 146, and then set the Height to 102, like so:

Excellent! Now run the app and have a look.

Well, it’s a little better, but the text is still really hard to read! Perhaps a lighter color would work better for the text on a dark background?

Open up Mainstoryboard.storyboard and select the timer label. In the Attributes tab, click on the black square next to Color to open up the color palette, as below:

In the color palette, select the Sliders tab and then select RGB Sliders from the pulldown menu. This will let you enter the red, green, and blue values for the label separately.

Set Red to 190, Green to 255 and Blue to 255, like this:

Note: After you set the color with the RGB sliders, the text might change to light blue or the entire label might turn into a light blue rectangle. Either result is okay! The color is being set and remember, the background image will be set from code in the viewDidLoad method.

Do the same set of steps for the score label. Select the score label, click on its color in the attributes to open up the color palette, and set the RGB slider Red to 190, Green to 255 and Blue to 255, like so:

Now run the project! Will this be it?

That looks great! Now not only have you made your first iOS app, but you’ve made a beautiful looking app! :]

Apps just aren’t about looks though — they need to sound great as well! To put the final polish on your app, you’ll be adding some music and sound effects in the next section.

Adding Sound

Music and sound effects are great ways to add character to your app. There are three sounds you’ll use in your app: background music, a beep every time the player taps the button, and a beep for every second that passes on the countdown clock — just to make the player sweat a little! :]

iOS supports all kinds of features such as GPS, accelerometer, and sound playback. Each of these features is bundled into something called a framework. You’re already using a framework called UIKit, which includes views, view controllers, buttons, storyboards, etc.

To play sounds, there’s a framework called AVFoundaton that you’ll need to use. To add it to the project, click on the Tap Me project at the top of the file browser in the left sidebar, as below:

Then click Tap Me under targets, and select the Summary tab:

Scroll down until you find a section called Linked Frameworks and Libraries. This is a list of all the frameworks currently in your app. To add more frameworks, click the + (plus sign) button.

Whoa — that’s a lot of frameworks to choose from!

Find AVFoundation.framework in the list and select it. Then click the Add button, like this:

Awesome! Now the AVFoundation framework has been added to the project. You’re ready to get grooving with some sound! :]

The sound playback will be handled from the view controller code, so the first step is to set up the header file. Open up ViewController.h. Near the top of the file, you’ll notice this line:

#import <UIKit/UIKit.h>

Hey, look at that! There’s the import statement for the UIKit framework. Add another import statement for the AVFoundation framework so that the code looks like this:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

Just as importing UIKit lets you use things like UIButton and UILabel, importing AVFoundation lets you use the very useful AVAudioPlayer class.

Next, you’ll need an instance variable for each of the three sounds. Add a line for each instance variable as shown below:

@interface ViewController : UIViewController<UIAlertViewDelegate> {
    IBOutlet UILabel *scoreLabel;
    IBOutlet UILabel *timerLabel;
 
    NSInteger count;
    NSInteger seconds;
    NSTimer *timer;
 
    // Add these AVAudioPlayer objects!
    AVAudioPlayer *buttonBeep;
    AVAudioPlayer *secondBeep;
    AVAudioPlayer *backgroundMusic;
}

That’s it for the header file! Time to get some sound playing. Open ViewController.m, and add this new helper method above the viewDidLoad method:

- (AVAudioPlayer *)setupAudioPlayerWithFile:(NSString *)file type:(NSString *)type
{
  // 1
  NSString *path = [[NSBundle mainBundle] pathForResource:file ofType:type];
  NSURL *url = [NSURL fileURLWithPath:path];
 
  // 2
  NSError *error;
 
  // 3
  AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
 
  // 4
  if (!audioPlayer) {
    NSLog(@"%@",[error description]);
  }
 
  // 5
  return audioPlayer;
}

This method will return an AVAudioPlayer object, and takes two arguments: a file name and type. Let’s look at what it does section by section:

  1. You need to know the full path to the sound file, and [NSBundle mainBundle] will tell you where in the project to look. AVAudioPlayer needs to know the path in the form of a URL, so the full path is converted to URL format.
  2. A NSError object will store an error message if something goes wrong when setting up the AVAudioPlayer. Usually nothing will go wrong — but it’s always good practice to check for errors, just in case!
  3. This is the important call to set up AVAudioPlayer. You’re passing in the URL, and the error will get filled in if something goes wrong.
  4. If something goes wrong, the audioPlayer will be set to nil, which you can check for with the exclamation mark symbol. If that happens, the error will be logged to the console.
  5. If all goes well, the AVAudioPlayer object will be returned!

Now that you have a handy method that will set up AVAudioPlayer objects, it’s time to use it! Add this code to the viewDidLoad method just after setting up the background images:

  buttonBeep = [self setupAudioPlayerWithFile:@"ButtonTap" type:@"wav"];
  secondBeep = [self setupAudioPlayerWithFile:@"SecondBeep" type:@"wav"];
  backgroundMusic = [self setupAudioPlayerWithFile:@"HallOfTheMountainKing" type:@"mp3"];

At this point in viewDidLoad, you’ll have all three sounds ready to be called in your code! :]

The first sound, buttonBeep, should play when the button is pressed. Update the buttonPressed method to play the sound:

- (IBAction)buttonPressed {
  count++;
 
  scoreLabel.text = [NSString stringWithFormat:@"Score\n%i", count];
 
  // add this line
  [buttonBeep play];
}

Run the project to test it out. You should hear a nice beep when you tap the button!

There are two other sounds to add. The secondBeep sound should be played every second when the timer ticks down. Add the call to play that sound in subtractTime method:

- (void)subtractTime {
  seconds--;
  timerLabel.text = [NSString stringWithFormat:@"Time: %i",seconds];
 
  // add this line
  [secondBeep play];
 
  // ...the rest of the method continues here...

Run the project again to test it out. You should hear a different beep as the number of seconds counts down. You’re almost done!

The final step is to add the background music. To play the music every time a new game is started, add the play code to the setupGame method. Add this code to the bottom of setupGame:

  [backgroundMusic setVolume:0.3];
  [backgroundMusic play];

You can adjust the volume of the background music so the beeps can still be heard. The setVolume method will take a number from 0 (off) to 1.0 (full volume); 0.3 is a good starting point for the background music.

Now run the project — and experience the glory of your fully featured app!

Feels good to be awesome, doesn’t it? :]

Final Thoughts

Congratulations! You have just made your first iPhone app, and taken it from having very basic functionality, to being a polished looking and sounding app.

There are lots of things that you can modify in your app, such as adding or changing some of the graphics, adding different difficulty levels, or even modifying the sound effects – the sky is the limit!

From here, you might want to try some of the other tutorials on this site. We have a ton to choose from – whatever your interests may be.

In the meantime, if you have any questions or comments, please join the forum discussion below!

This is a blog post by Tutorial Team member Mike Jaoudi, a Computer Science major at New York University. You can find Mike on Twitter and .

Mike Jaoudi

Mike Jaoudi is a Computer Science major at New York University. For the past couple of years, Mike also worked as an Instructor and Curriculum Developer at iD Tech Camps for iOS App Design and iOS Game Design. While at iD Tech, Mike discovered an enjoyment for teaching, as he’s found that “when you teach you learn twice”. He is a fan of the BBC show “Sherlock” and NCAA fencer. Check out his multiplayer snake game, Snakez.

Comments

Add a Comment

Username:     Password:    

User Comments

8 Comments

  • Oops!
    Sorry, it seems that the page you are looking for does not exist.
    Try searching to see if you can find it that way!
    romox
  • UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Time is up!"
    message:[NSString stringWithFormat:@"You scored %i points",count]
    delegate:self
    cancelButtonTitle:@"Main Menu"
    otherButtonTitles:nil];
    [alert show];


    On my end I have a main menu and I can press Play and the game will start and whatever how would I make the text that pops up after the time runs out be able to say Play Again or Main Menu?
    Also how would I be able to add the same background color to the menu as in the game's interface?
    Thanks in advance for the help!

    -EDIT-

    I did find out how to make another button, now I just need to know how to be able to link it to the Main Menu.

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Time is up!"
    message:[NSString stringWithFormat:@"You scored %i points",count]
    delegate:self
    cancelButtonTitle:@"Play Again"
    otherButtonTitles:@"Main Menu", nil];

    [alert show];
    RAGGED_BLADE
  • Great Tutorial!Thanks a lot
    I am looking forward you can add another topic that how to save the highscore and show the highscore on the screen,that will help us a lot.
    HowShin Wang
    howshin
  • Awesome Tutorial! Great place to start when learning to code iOS Apps! So much easier then reading the mundane books! Thanks!
    Antonyk86
  • You have done a terrific job with this tutorial. The images and the app looks absolutely superb when i completed it.

    Just one thing that I noticed when running it is a particular scenario:
    1. Suppose when the timer times down to 0, the background music has just a few seconds more to play
    2. When we call backgroundMusic.play, since there are a few seconds of the music left, it just continues to complete playing it. So once it gets over, there is no background music till the 30 seconds are up.

    So what i did is:
    1. In the alertView:clickedButtonAtIndex, I stopped the background music playing using [backgroundMusic stop];
    2. In setupGame, instead of [backgroundMusic play], I used backgroundMusic.currentTime = 0; [backgroundMusic play]; This causes the background music to start at the beginning each time.
    User avatarRachnaAnil
  • When I try to build it after I have already added all the necessary AVAudioPlayer coding I get an error that is telling me that there is no visible @interface for AVAudioPlayer. I'm guessing there has to be something extra added to the header file?

    Any help is great, I'm very new to this.

    Thanks! :D
    DARKUNIT22
  • First off, the tutorial has been really awesome so I wanted to say thank you for that!

    My problem now is I have four errors that are not allowing me to build and run my program. Everything was great up until I tried to add sound and now I am faced with these issues:

    // 3
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];


    I get an error: Use of undeclared identifier 'url' and I'm not sure why?

    My second problem is:

    buttonBeep = [self setupAudioPlayerWithFile:@"ButtonTap" type:@"wav"];
    secondBeep = [self setupAudioPlayerWithFile:@"SecondBeep" type:@"wav"];
    backgroundMusic = [self setupAudioPlayerWithFile:@"HallOfTheMountainKing" type:@"mp3"];


    I get three errors (one per line) that are all the same.

    No visible @interface for 'ViewController' declares the selector 'setupAudioPlayerWithFile:type:'

    I have checked and rechecked my code to make sure I copied it correctly but I can't seem to spot what I am doing wrong here..any help would be immensely appreciated.

    Thanks,

    James
    Fenderkid
  • @Fenderkid

    Double-check your viewDidLoad and setupAudioPlayerWithFile:type methods.

    re: "undeclared identifier: url" error
    url is defined after the "// 1" comment.
    Code: Select all

    // 1
      NSString *path = [[NSBundle mainBundle] pathForResource:file ofType:type];
      NSURL *url = [NSURL fileURLWithPath:path];  // <---- url declared here


    Check the spelling of your setupAudioPlayerWithFile:type: method. Remember, Objective-C is case-sensitive.

    If you're still stuck, post the contents of your viewDidLoad and setupAudioPlayerWithFile:type methods.

    Good luck!
    rcasey

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Gaming tutorial votes. This week: Non-Gaming!

    Loading ... Loading ...

Last week's winner: Advanced UIView Animations. Coming soon!

Suggest a Tutorial - Past Results

Our Books

Our Team

Tutorial Team

  • Joshua Newnham
  • Colin Eberhardt
  • Pietro Rea

... 42 total!

Editorial Team

  • Ray Wenderlich
  • Brian Moakley
  • Chris Belanger

... 9 total!

Translation Team

  • Sonic Zhao
  • Hiroshi Kawamoto
  • Lin Ma

... 27 total!

Subject Matter Experts

  • Richard Casey
  • Adam Eberbach
  • Marcio Valenzuela

... 5 total!