Sunday, April 24, 2011

Build an iPhone app



Developing for the iOS App Store is a no-brainer. If I said that a measly investment of £250 was enough to open up a market of 150 million consumers, the ears of any smart developer should prick up.

If I were to add that many of those consumers are Apple fans eager to part with their cash in an attempt to purchase software justifying the cost of their hardware, then you might well start to see why there are now 300,000 iPhone apps and 60,000 iPad apps two and a half years after the App Store launched.

The sheer size of the App Store is staggering, with more than twice as many apps available as all the competing stores combined.

In this article I want to help kick start your own development on the App Store, and I hope it's encouraging for you that I myself went from having zero apps to having 20 approved and on sale in the space of just over a year and a half. I haven't made enough money from them to retire, but they do provide a regular income - and it's an income that's only going to grow as Apple sells more hardware.

All you need to join in is an idea, a Mac (for coding), and this tutorial. Let's go!

Requirements


To make software for iOS devices - that's iPads, iPhones and iPod Touches - you need just one software package: the iOS SDK from Apple.

This comprises four major components: The Xcode development environment, in which you'll be writing all your code; Interface Builder, which is a drag-and-drop user interface design system; libraries and header files for writing your code in Objective C (the iPhone's native language); and the iOS Simulator, which lets you run a virtual iPhone or iPad on your Mac.

I should stress that this can only be done your Mac, because the iOS SDK isn't available for any other platform. In fact, you're pretty much limited to using Apple's hardware, software and development tools. This is why many people refer to iOS development as being as a 'walled garden' - Apple is very protective about who makes apps and what goes into the store.

The Mac requirement is a hurdle you can't really vault over, but I will say this: even if you're dedicated to Windows or Linux, a Mac is an excellent purchase. We rarely see more solid or reliable PCs.

SIMULATOR: You can test out your app on your desktop with the use of a simulator - should save you some money on an iOS device for testing
Anyway, if you plan to work only inside the simulator, you don't need to pay Apple any money for a test device or a developer account - you can go straight to http://developer.apple.com/ios and get access to the free tools.

If you later decide you've built an app you want to sell, you should pick up an iPod Touch for testing purposes (£180), then sign up for a commercial iOS account (£60). If your 59p app sells just 500 copies - if just 0.00033 per cent of iOS owners buy it - you've made your money back and everything else is profit.

Once you've created your account, you need to download the latest SDK. At the time of writing, that's Xcode 3.2.5 with iOS SDK 4.2. This package includes everything you need to make iPhone and iPad apps.

The installer is very simple: just click 'Next' until the copying process starts, then give it about 30 minutes to perform its magic and you're ready to get going.

Building your project

I'm not interested in teaching you theory here - I want to show you how to make a real project so that, if you want, you can extend it with your own customisations and make your own valuable addition to the App Store.

We're going to make a simple to-do list manager, building on some of the basic user interface elements that are common to iOS apps.

First, fire up Xcode - you should find it in the 'Developer | Applications' folder on your hard drive. A welcome screen should appear, but you can close that and choose 'New | New project' from the menu.

Apple includes seven application templates out of the box, but the one that's most useful to begin with (primarily because it comes with a fair amount of code written for you) is the navigation-based application. Choose that, then name it 'TaDaList' and save it to your desktop.

A navigation-based app gives you a UI similar to the Settings app - you get a title bar at the top and a table of options to choose from. Choosing any option will cause a new screen to pan in from the right. You can then go back to the previous screen by tapping a 'Back' button - it's all very intuitive and easy to learn.

You can see the basic application template that Apple has created for you by pressing [Command]+[Y] to build and run your app in the simulator. You can see the Apple blue bar at the top (it's blank because we haven't typed anything in there yet), plus the table of information (again empty because we haven't told the app what should go there).

Define items
X-CODE: Xcode is your primary development environment for iPhone. Some people like it, most don't
Before we type any to-do list items into the table, we need to define what those items are and where they're stored.

First, think about what we need each to-do list item to be stored as, and how they might helpfully be stored as a group. You should come up with these two key points: Firstly, a to-do list item, like 'Feed the cat' or 'Take over the world', is just a string.

In Objective C, there are two types of string: 'NSString' and 'NSMutableString'. The only difference between the two is that the latter can be changed after it has been created.

Secondly, the collection of items is very simple: as they are added, we need to put them either at the beginning or end of our existing list. Users need to be able to read them in any order they please. This calls for a pretty standard array, although again there are two on offer - 'NSArray' and 'NSMutableArray'. Hopefully you can figure out the difference.

In this project, we'll be using the mutable versions of both of those classes. We need mutable strings because users need to be able to edit to-do entries, and the easiest way to do that is to let them edit the entries in place. We also need a mutable array, otherwise users wouldn't be able to add and remove items.

So, let's start with the array: we're going to use a very basic programming technique in Objective C called 'properties'. The syntax for these is a little verbose, so I recommend that you commit it all to muscle memory as quickly as possible.

Properties


Our to-do list items need to be stored in an NSMutableArray, and the correct way to create that NSMutableArray is with a property. This is a little bit of Objective C syntactic sugar that means 'When I try to get the value, run this method, but when I try to set the value, run this method instead.' It's all about the methods, as opposed to setting values directly.

Having to write two methods to get and set each value is clearly an annoyance, so Objective C has special syntax that can generate those methods for us when the code is compiled. If you ever choose to write your own, just tell it to stop auto-generating the methods that you want to replace - easy.

First things first, we need to tell Objective C that we want an NSMutableArray for our items. In 'RootViewController.h' - the definition file for our main table view - modify the definition of the class to be as follows:

@interface RootViewController :
UITableViewController {
NSMutableArray *items;
}
@property (nonatomic, retain)
NSMutableArray *items;
@end

At first, that probably looks like we're declaring the 'items' array twice, but there's a difference: the first declaration makes the variable so that it can be used anywhere inside the class, but the second declaration turns it into a property so that it can be used anywhere in our code.

What's more, the keyword 'retain' tells Objective C that if it generates the code for us, it should make sure and keep the object alive until we say otherwise.

I say "if it generates the code", because that's still to come - change to the 'RootViewController.m' file and put this line of code immediately beneath '@implementation RootViewController':

@synthesize items;

That's the bit that makes the code generation happen - with that single line, Objective C will turn our '@property' into two methods, both doing memory management for us automatically.

There's one last piece, though: using 'retain' keeps the 'items' object alive until we say otherwise. If you never say otherwise, that memory is never freed up - even if you can't access it any more. As a result, you should always free memory that you've retained, so scroll to the bottom of the 'RootViewController.m' file and look for the 'dealloc' method. Change it to read as follows:

- (void)dealloc {
[items release];
[super dealloc]; }

Sending the 'release' message to an object - which is what this code does - has the effect in this example of freeing the memory. It's actually a little more complicated than that, but it works well enough for now.

Filling the table

Now that we have an items array declared, we can create some items and show them in the table. But first, we need to create the items array. And now, thanks to the amazing power of magazine telepathy, I can read your very thoughts: "Wait a minute… didn't we just write some code to do all that?"

Well, not quite. We wrote code to declare the variable so that it's available to use - now we need to use the thing.

Near the top of 'RootView Controller.m' the 'viewDidLoad' message has been commented out. Remove the '/*' and '*/' to uncomment it, then add this to it:

self.items = [NSMutableArray
arrayWithCapacity:10];

With that in place, our array is ready to be used. Scan down the file a little and look for the 'numberOfRowsInSection' method - that determines how many rows appear in the table in our UI.

How many? Easy - as many as we have items in the 'items' array. Right now, the default method implementation has 'return 0', meaning '0 rows'; change that to return the number of items in 'items':

return [items count];

Next, we need to change the way table rows are created so that they show the text of the correct to-do list item. As with the other methods, Apple's template already includes code to do most of this work - in fact, you just need to add one line that says 'set this row's text label to have whatever is in our items array at that position'.

About halfway down the 'RootViewController.m' file is the 'cellForRowAtIndexPath' method, and you should be able to see that it receives a parameter called 'indexPath' - that tells us which row we need to load. So, directly beneath the comment that reads 'configure the cell', add this:

cell.textLabel.text = [self.items
objectAtIndex:indexPath.row];

That uses the row's position as passed in 'indexPath' to look inside the 'items' array and assign the correct text to the table row. However, if you run the app it still doesn't do anything, even after all this code.

Fortunately, that's just a matter of us not having any items in the array, so we need to add a button to the navigation bar at the top that lets users add new items.
Adding new items
This is actually two tasks: adding a button, and writing the code to respond to the button being tapped. The first task is very simple - in the 'viewDidLoad' method, put this line of code:

self.navigationItem.
leftBarButtonItem =
[[[UIBarButtonItem alloc] initWithBa
rButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@ selector(addTapped)] autorelease];

That does several things at once, so let me break it down:

'self. navigationItem.leftBarButton' means that we're setting the left button (each navigation bar can have one button on the left and one on the right).

'UIBarButton Item alloc' creates the new button, and 'initWithBarButtonSystem Item' creates the button using the 'UIBarButtonSystemItemAdd' style. This means it will be displayed with a '+' symbol.

'Target:self' means that when the button is tapped, the message saying so will be passed to 'RootViewController.m'.

'@ selector(addTapped)' is how 'RootViewController.m' will be told the button was tapped - the 'addTapped' method will be run.

'autorelease' decrements the use count of the button. It won't be freed, though, because the 'leftBarButton' will retain it. That single line of code creates a new button with a '+' symbol and sets it up to call 'addTapped' in 'RootViewController.m' when it's tapped, then add its to the navigation bar.

We don't actually have the 'addTapped' method yet, but it's not complicated - all it needs to do is create a new 'NSMutableString' with some default text in, then reload the table so that it appears.

Put this new method somewhere in your 'RootViewController.m' file:

- (void)addTapped {
[self.items
addObject:[NSMutableString
stringWithString:@"New Item"]];
[self.tableView reloadData];
}

As you can see, to add an object to an NSMutableArray you just need to use the 'addObject' method, although what follows might confuse you a bit - it creates a new NSMutableString out of a plain text string.

Note that all NSStrings in Objective C must start with '@' to distinguish them from plain C character constants.

If you run the app now, you can add new rows by tapping the [+] button. It's still not useful though, because you can't actually edit anything - let's do that next.

Off into IB
INTERFACE BUILDER: The UI is split across four windows, so if you were planning to use a 13in MacBook for your coding, you might want to reconsider
We're on the last leg of our project now. Only one thing remains: we need to be able to edit to-do list items. When a new item is added, we create it as a mutable string and add it to our collection, so all we need now is a simple user interface to allow editing of items.

Right-click 'Classes' and choose 'Add | New file'. Select 'UIViewController subclass' and leave the checkboxes below deselected, except for the one marked 'With XIB for user interface' - that's the bit that lets us drag and drop user interface elements as we need them.

When you're asked for a name, call it 'EditController' - this is what we'll be using to edit to-do list items, and Xcode will create 'Edit Controller.h', 'EditController.m' and 'EditController.xib' for us.

It's the last one we're interested in - it's an XML file that can be edited by Interface Builder, so double-click it to open it in IB.

Interface Builder

Interface Builder is made up of four main windows: the Library, which showcases all the UI components you can use; the Workspace, which is the graphical layout view where you can create your user interface masterpieces; the Document Window, which shows you a tree-based version of your layout; and the Inspector, which is where you can set various properties of your interface.

Right now we want the workspace, so look in the Document Window for 'View' (it'll be under 'File's owner and first responder') and double-click it to bring up the Workspace. This will be a big, empty white space, with a small grey iPhone status bar visible at the top.

You need to go to the Library window and drag a Text View into that white space. When you hover over the space, you'll see the Text View stretch to take up all the available space; let go, and you'll drop it in there.

Using the Inspector, delete all the default text that's in the Text View. In order to use the Text View in our app, we need to add it as a property (which follows the same four steps as before), then hook it up in IB. Let's tackle the property part first.

In Xcode, modify 'EditController.h' to this:

#import <UIKit/UIKit.h>

@interface EditController :
UIViewController {
UITextView *textView;
}

@property (nonatomic, retain)
IBOutlet UITextView *textView;

@end

In the '.m' file, you need to add @ synthesize textView; beneath '@ implementation EditController', and add [textView release] into the 'dealloc' method - just as we did for the 'items' property in 'RootViewController.m'.

There's one small difference here, and that's 'IBOutlet'. When IB is looking for things to connect to, it scans your source code for IBOutlet, so adding that to our property basically means 'This is something we want to use in IB.'

Save all the files in Xcode, then switch back to IB. Because we've told IB that 'textView' is of interest to it, we now just need to connect the 'textView' variable inside the 'EditController' class to the Text View we drew in the workspace window.

To do that, look for 'File's owner' in the Document window, hold down [Ctrl], then click and drag a line from there to the text view, and let go. A menu will appear showing the list of possible connections, and you should see 'textView' in there. Click it and you're done - save the file and close the file.

We've already launched IB, so there's one more thing we need to do: give our navigation bar a title. To do that, go into Xcode and double-click 'MainWindow.xib' from under the 'Resources' folder. When it loads into IB, doubleclick the navigation bar at the top and give it the text Ta Da - this will be used to generate the back button too, so it's quite important.

Editing items

With our simple user interface done, the next step is to make it appear when one of our to-do list items is tapped. That's controlled in 'RootViewController.m', in the 'didSelectRowAtIndexPath' method.

Apple has put some code in there that we can make use of - uncomment it, then change the two instances of 'DetailViewController' (with a capital D!) and the single instance of 'Nib name' to 'EditController'.

Before that compiles, you need to tell Xcode you want to draw upon the 'EditController.h' file you made earlier, so switch to the 'RootViewController.h' file, and add this just beneath the existing #import line:

#import "EditController.h"

That handles creating and showing the editing window, but it doesn't actually show the to-do list text in the view - we need to do that ourselves by passing in the selected string in for editing.

The first part of that is to create an 'NSMutableString' property inside 'EditController' called 'todoItem' I've already shown you how to complete all four steps in the process of creating properties, so just repeat them here.

The interesting bits are how to show the text of the to-do item in the view, and that's done back in 'RootViewController.m' - before the call to 'pushViewController' is made in 'didSelectRowAtIndex Path', you just need to set the 'todoItem' variable like this:

detailViewController.todoItem =
[self.items objectAtIndex:indexPath. row];

That uses 'indexPath.row', which, if you remember, tells us which table row we're dealing with - to pull out the correct 'NSMutable String' from the 'items' array, and stores it in the 'EditController'.

Once that's step is complete, we can make the text appear in our UI by uncommenting the default 'viewDidLoad' method in 'EditController.m' and added this single line of code:

textView.text = todoItem;

So, when the view loads - which happens immediately after the call to 'pushViewController' - we set the text view's text according to the item we passed in. Perfect!

Final tweaks

At this point we can list items, add items and bring up the editing window, but any changes that are made aren't saved. This is really easy to change though, because it's just a matter of waiting for the user to go back to the previous view, and then grabbing 'textView.text' and saving it.

The 'go back to the previous view' event is sent to us in the form of 'viewWill Disappear', which 'EditController' receives whenever it's going to be replaced by any other view.

In 'EditController.m', you need to create a 'viewWillDisappear' method - make sure you follow Apple's example and call the same method on the super class before doing your own thing. Here's what it should look like:

/- (void)viewWillDisappear:(BOOL) animated {
[super viewWillDisappear:animated];
[todoItem setString:textView. text];
}

The interesting bit there is the call to 'setString', which changes the contents of an 'NSMutableString' to some new text. This 'NSMutableString' is shared between the 'EditController' and the 'RootViewController', which means we're changing our master copy of our to-do list item.

There's just one last thing to do before we can call this project finished, which is to update our 'RootViewController' table when a to-do list item has been edited.
We've just 'viewWillDisappear' in 'EditController', so now we need to work with its counterpart, 'viewWillAppear', in 'RootView Controller'. Again, you'll find a commented-out version already in there, towards the top, so all you need to do is remove the comment marks, then add this single line of code to the method:

[self.tableView reloadData];

We have that 'tableView' because we inherited from 'UITable ViewController', and when you call 'reloadData' it then restarts the entire process of asking how many rows there are and what those rows contain.
APP VIZ: Once the money starts rolling in, you'll find that Apple's sales tracker is rather inadequate for monitoring your app's performance


That's the end of the project - we're not doing a whole lot here, but if you've absorbed everything in these pages you'll have a great grounding in the core concepts of iOS app development, including memory, view controllers, Interface Builder, strings and arrays, and of course iTunes Connect - the bit where you can actually make money!

But there's no point in learning all this if you don't use it, so if you want all this abstract knowledge to bed down properly in your brain and become genuinely useful, it's time to put what you've learned to work and get started on making your first app.

It doesn't need to be some incredible, fortune-making idea, but if you do come up with something great and happen to make a mint from your efforts, don't forget who taught you!




No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...