2/15/2009

Differences Between the Simulator and Device

If you've done a bit of iPhone development, you've probably run into scenarios where the simulator and your device behave differently. Generally speaking, it's because the simulator uses OSX's libray (I think) and is a bit more "friendly" to errors, whereas the iPhone is missing a couple things here and there and is much more picky about errors. Case in point - comparing strings. With the simulator, you'll find that the following statement probably works fine:

if (myTestString == @"Blah blah blah") dosomethingcool;

However, the device will balk and possibly crash. What you're supposed to do, and the thing that works on the iPhone, is:

if ([myTestString isEqualToString:@"Blah blah blah"]) dosomethingcool;

In another example, you'll see my entry below about NSUserDefaults. My pro-tip there is that loading an NSMutableArray results in an immutable (uneditable) array, but only on the device. In the simulator, I was able to make changes and everything worked OK (it seemed anyway). But on the device things were effed. So the lesson is: test on your device early and often.

As a final note, and something that I'm beginning to find very useful for a number of reasons, is a little app called AppKiDo. Basically, it lets you quickly browse through the different foundations and included methods and check out their properties, methods and so on and so forth. So, you can look up NSString and easily see what sorts of things you can do with it, or look up AVAudioPlayer and see what its properties are. You can get all this from the docs, but AppKiDo makes it way easier and faster to do so, in my opinion. And since you can have it work specifically for the iPhone, you can more easily find out if a piece of code that you found online is actually supported or not.

Save Your App's State (and Settings)

The iPhone (and I suppose Cocoa as well) makes it very easy to save and retrieve data. Most commonly, this will be settings of some sort, but you could save the state of your app so that when someone starts it again, it picks up from the same place, or something similar.

What you want to use is NSUserDefaults. Using it is extremely simple. First, just declare your NSUserDefaults pointer.

NSUserDefaults *myDefaultOptions = [NSUserDefaults standardUserDefaults];

To save an object (or variable), do something like the following:

[myDefaultOptions setObject:myTestString forKey:@"firstPlayerName"];

In this case, "firstPlayerName" is the name of the key that I'm saving the object to. It can match your in-use variable name if you want (which I often do). You might want to make a save method that gets called with a button press and writes out a bunch of objects at one. When you want to then to load the object again:

myTestString = [myDefaultOptions stringForKey:@"firstPlayerName"];

Basically, that's it, but you'll need to run a test on your loads so that when someone runs the program for the first time (or hasn't saved), then you'll take care of it. In the case of a string, if there isn't a corresponding NSUserDefaults entry for what you try to load, it comes up as NULL. So, after loading the save, you could run a quick check like the following:

if ([myTestString == NULL]) myTestString = @"Blah blah blah";

PRO-TIP: You can save arrays to NSUserDefaults and retrieve them easily, but there's a catch - even if you save out an NSMutableArray (one that's editable - NSArray is not), it will come back as immutable (uneditable). I ran into some crazy issues because of this, and it wound up being a pain to track down until I figured it out. It's actually an easy fix though - just add "mutableCopy" to the end of your read. So, it would look something like:

myArray = [[defaultOptions objectForKey:@"mySavedArray"] mutableCopy];

1/24/2009

Link to an App Store Page From Your App

If you have more than one app for sale on the App Store, it's a good idea to cross-promote your applications. For my newer apps, I've created a second view with a handful of links to my older stuff.

Making your app open up an App Store link is a simple. Just create a button and a method that gets called when you tap the button. In said method, all you need to do is put the following line:

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=299681466&mt=8"]];

Just replace the link there with your own from iTunes and you're all set.

PRO-TIP: When you go to iTunes and choose to copy the URL, it'll start with "itunes.apple.com/Webblahblahblah". Replace the "itunes.apple.com" part with "phobos.apple.com", just like how I have it in the example above. If you leave the itunes URL bit, your app will first open Safari, which will then in turn open up the App Store. Changing the itunes part to phobos will cause the App Store to open directly and the process will be faster and look much cleaner to your users.

1/13/2009

Hide the Status Bar

Here's a quick one. If you want to get rid of the status bar at the top of the screen to make more room for your content, head into your AppDelegate.m file, find the applicationDidFinishLaunching method and simply add in this line:

[[UIApplication sharedApplication] setStatusBarHidden:YES];

Presto-chango, the status bar will magically disappear.

PRO-TIP: If you find that after you run your application that your content kind of pops up on the screen to fill in the space, leaving an empty space at the bottom, select your view in Interface Builder and go to the measurements tab. Make sure the sizing height is set to 480 and not 460.

AVFoundation and Audio

There are a couple different ways to play audio on the iPhone and iPod touch. There's OpenAL, Audio Queues, SystemSounds and, introduced in firmware version 2.2, AVAudioPlayer from the AVFoundation framework. AVFoundation will eventually have a whole lot more to it, including video playback and the like, but AVAudioPlayer is a good start.

The nice thing about AVAudioPlayer is that it's a piece of cake to use. The downside is that it isn't instantaneous, so you’ll get a slight pause before the sound plays. So, I’ve found that it’s great for playing alerts and things like that, but not for anything that requires immediate playback, like games or a virtual piano.

Loading a sound and playing it is simple. To load a piece of audio, use something like this:

AVAudioPlayer *myExampleSound;

NSString *myExamplePath = [[NSBundle mainBundle] pathForResource:@"myaudiofile" ofType:@"caf"];

myExampleSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:myExamplePath] error:NULL];

myExampleSound.delegate = self;

The second and third lines are fairly common for loading files – point to the file, then assign said file to your variable. The third line, which I believe is optional for simple stuff, basically tells the view (I think) to pay attention to the sound so that you can monitor what it’s doing.

Anyway, once the file is loaded, playing (and stopping) it is simple. Those commands look like:

[myExampleSound play];
[myExampleSound stop];

Before you play the sound, you can use:

[myExampleSound prepareToPlay];

to get it ready. AVAudioPlayer will do this for you automatically when you call the play method, but you then get a tiny bit more lag. If it’s a short sample, you’ll probably be fine without it.

Aside from playing and stopping the sound, you can tweak it in a few ways. Here are two examples:

myExampleSound.volume = 0.5;
myExampleSound.numberOfLoops = 2;

Obviously, the first one sets the volume (from 0 to 1.0) and the second can be used to repeat the sound multiple times in a row.

There are a couple more things you can do with AVAudioPlayer, though I haven’t played around with more myself. For instance, it sounds like you can monitor whether or not a sound is currently playing, which can certainly be helpful.

Welcome

My name is Chris Roper and I'm an amateur iPhone developer. As of this writing, I have four applications on the App Store with my next one set to go up tomorrow (if it's approved by Apple in time) and a sixth nearly done. They aren't complicated applications by any means, but they're fun projects, good learning experiences and help to bring in a little extra cash.

Learning to program for the iPhone hasn't been easy - I majored in computer science for three years at Virginia Tech, but that was more than a decade ago. I never got into Mac programming, so my experience with Objective-C was basically nil. So while I have the fundamental knowledge for how things work, I had to start from scratch with learning most of the syntax, the development environment, single-window UI techniques and more.

My hopes are that by sharing bits of code that I've picked up, I'll be able to help others at a similar starting point get up to speed a little quicker. Please post in the comments and offer up different (or better) ways to handle things, alternative methods that could be useful in other situations and whatever else you can or want to post.

Thanks.