iOS 5 By Tutorials ebook

Monthly Archives: December 2010

MHRotaryKnob, a rotary knob control for iOS

Music software often has knobs that you can turn to set the volume or panning. A few days ago I wrote MHRotaryKnob, a UIControl that lets you do the same on the iPhone or iPad. Some rotary knobs can turn forever (such as the old iPod wheel) but this one has a minimum and a maximum, so it can only go round once.

MHRotaryKnob example

This control is open source. You can download it from my Github page.

In this blog post I will explain what goes into writing your own controls. I’ll use my implementation of this rotary knob as an example. Continue reading…

Sound Synthesis on the iPhone

Recently I completed an iPhone/iPad project for a client that required real-time sound synthesis. I’ve been playing with sound synthesis for a while now; I even uploaded an example project to github a few months ago that illustrates how to do this. In this blog post I am not going to explain the basics of sound synthesis — for that, I will point you to this excellent article. Here, I will just explain how to do it on iOS. Continue reading…

New App: Perfect A

I just received word that Perfect A is now available from the iTunes App Store.

Perfect A is a tuning fork application that I wrote for a client a few weeks ago. It is a very basic app that uses real-time sound synthesis to produce a reference tone for tuning musical instruments.

Even though it is possible to create a tuning fork app that does not use real-time sound synthesis, using it allows you to change the pitch in 0.01 Hz increments as the sound is playing. You can also choose between two waveforms suitable for tuning.

(If you are interested in audio, I will soon publish a blog post with in-depth information about how to do sound synthesis on the iPhone.)

Screenshot of the Perfect A tuning fork app for iPhone and iPad

Perfect A is a universal app, which means it can run on both the iPhone and the iPad. Even with an app that is as simple as this one, there are differences in the user interface between these two devices.

When you press the “i” icon on the iPhone, the screen flips to reveal an options menu. On the iPad the options are shown in a popover instead. Little things like that make it necessary to re-think the user interface when you develop for the iPad. In the case of Perfect A these differences are only small, however, I’m working on another app at the moment where the disparity is much greater.

One interesting thing about the Perfect A project is that I did not do this for money. The client could not meet my asking price but offered an enticing alternative: in exchange for developing this app for him, the client would give me a database that I could use in my own Reverse Chord Finder app. Now, I don’t intend to make a habit out of getting paid by bartering, but it shows that with some creativity it is possible to get an app developed for little or no money.

iTunes App Store link for Perfect A

For more information: perfecta.mennigmann.com

How to Program for Low Memory Conditions

Recently I wrote a flashcard app for a client that uses a lot of images. On my old iPhone 3G the app often gave memory warnings and in certain situations was even terminated because it could not free up enough memory. That is something you want to avoid! Newer iPhone models have more memory to spare but low memory conditions can still occur. Your app should be prepared to handle those situations.

View controllers will unload their views

If memory gets tight and you have one or more view controllers that are not currently displaying their views – for example they are hidden behind a modal view – then these controllers will unload their views. When such a view controller becomes active again, it will reload its NIB and the views contained in it.

You need to help the view controller unload its view by implementing the -viewDidUnload method. Here you release all references you keep to retained UI elements, such as buttons, labels and text views. Basically you need to release all your retained IBOutlets and set their pointers to nil. Since you’re probably using properties for these IBOutlets, it’s as simple as nilling them:

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.myButton = nil;
    self.someLabel = nil;
}

When the view controller reloads its view, it loads its NIB again and makes new instances of all the views in it. If any of the old views are still around, then they are no longer used for anything; their pointers will be overwritten to point to the new views. So if you don’t release your retained UI elements in -viewDidUnload then they will stay in memory and you’ll have a memory leak when the view reloads.

Note that -viewDidUnload is not called when the view controller is deallocated. It is only used in low memory conditions. So you’ll have to do the same work of releasing any retained objects in -dealloc. I usually create a -releaseObjects method that I call in both.

- (void)releaseObjects
{
    [myButton release], myButton = nil;
    [someLabel release], someLabel = nil;
}
 
- (void)viewDidUnload
{
    [super viewDidUnload];
    [self releaseObjects];
    // free up anything else here that you can get rid of
}
 
- (void)dealloc
{
    [self releaseObjects];
    // free any other objects that may live beyond the view
    [super dealloc];
}

Note that in -releaseObjects I don’t use the properties. Instead I specifically release the object and then set its pointer to nil. This is because this method will also be called from -dealloc. Many developers consider it not a good idea to call accessor methods from -dealloc (which is what happens when you use a property).

An example

It is important to realize that -viewDidUnload and -dealloc are not entirely the same. They both release view-related stuff, but typically -dealloc does more. When the view controller’s view is unloaded for memory reasons, the controller itself stays around. So you may not want to release all of your ivars in -viewDidUnload.

Let’s say we have a MainViewController that owns an NSMutableArray named “favorites”. It presents a modal table view controller, FavoritesViewController, that lets the user delete favorites from the list. Whenever the user deletes a favorite, FavoritesViewController notifies the MainViewController that the list has changed through a delegate method.

If MainViewController‘s view gets unloaded while the FavoritesViewController is showing, then we don’t want to release its “favorites” array in -viewDidUnload. We will still need to make changes to that array while the user is interacting with the FavoritesViewController. But we do want to release “favorites” in MainViewController‘s -dealloc, because then we’re truly done with it.

In code that would look something like this:

@interface MainWindowController : UIViewController
@property (nonatomic, retain) NSMutableArray* favorites;
@property (nonatomic, retain) UIButton* someButton;
@property (nonatomic, retain) NSDictionary* lookupTable;
@end
 
@implementation MainViewController
 
@synthesize favorites, someButton, lookupTable;
 
- (id)init
{
    if ((self = [super init]))
    {
        self.favorites = [NSMutableArray arrayWithCapacity:10];
    }
    return self;
}
 
- (void)viewDidLoad
{
    self.someButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
 
    // This is some object that we only need while the view is showing.
    self.lookupTable = [NSDictionary dictionaryWithObjectsAndKeys:.....];
}
 
- (void)releaseObjects
{
    // We don't need these objects anymore if we don't have a view.
    [someButton release], someButton = nil;
    [lookupTable release], lookupTable = nil;
}
 
- (void)viewDidUnload
{
    [super viewDidUnload];
    [self releaseObjects];
 
    // Note: we don't want to release favorites here!
}
 
- (void)dealloc
{
    [self releaseObjects];
    [favorites release];
    [super dealloc];
}
 
// This is the delegate method.
// It may be called when our view is not loaded.
- (void)favoritesViewControllerDidDeleteFavorite:(id)favorite
{
    [favorites removeObject:favorite];
    if ([self isViewLoaded])
    {
        // Update the view...
    }
}
 
@end

Alternatively, you could initialize the favorites list in -viewDidLoad like this:

- (void)viewDidLoad
{
    ...
 
    if (self.favorites == nil)
        self.favorites = [NSMutableArray arrayWithCapacity:10];
}

You have to check to see if it already exists because, as should be obvious by now, -viewDidLoad may be called more than once.

Another way to do this is to make the property’s getter perform lazy loading:

- (NSMutableArray*)favorites
{
    if (favorites == nil)
        self.favorites = [NSMutableArray arrayWithCapacity:10];
    return favorites;
}

Now you don’t have to initialize it anywhere! Note that this requires that you refer to favorites as “self.favorites” where you want to use it, not just as the ivar “favorites”.

The rule of thumb is that -viewDidUnload should free as much data as possible. You should only keep enough state information in order to restore the view to its full state when the view controller becomes active again. In the above example, we didn’t need to keep “lookupTable” alive beyond the lifetime of the view but we did need to keep “favorites” around.

But you can do more!

Your view controllers are also notified of low memory situations with the -didReceiveMemoryWarning method. You should override this method to release any data that you do not need at that specific moment. Your app delegate also has a similar method, -applicationDidReceiveMemoryWarning, and other classes can subscribe to the UIApplicationDidReceiveMemoryWarningNotification
notification message.

The trick is to set things up so that as many objects as possible can be released when memory gets tight. But you don’t want to release them all the time, only when necessary. If you always release an object that the app might need again a second later, then this leads to a lot of extra processing and will only drain the battery faster.

For example, the flashcard app uses a CardView class. This is a UIView subclass that serves as a container view for two subviews: the back of the card and the front of the card. Initially, the back is shown. When the user taps it, the card flips over with an animation.

Should the iPhone give a low memory warning when the front of the card is showing, the app will unload the back image. We don’t need it at that point because it is not visible. Only when the next card is shown, the back image is automatically loaded into memory again.

What makes this work is “lazy loading”. Lazy loading is a good principle to use in as many places as possible. It requires a little extra logic and planning on your part, but that’s still better than an app that spontaneously crashes.

Properties and lazy loading go well together. You write the getter method yourself and make it do lazy loading. Then you always access the object through the property. In that case, if the object got unloaded out from under you, it will be reconstructed on-the-fly.

For example, here is an excerpt from the CardView class:

@interface CardView : UIView
{
    BOOL showingBackView;
}
 
@property (nonatomic, retain) UIImageView* backView;
@end
 
@implementation CardView
 
@synthesize backView;
 
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
 
    if (!showingBackView)
    {
        [backView removeFromSuperview];
        [backView release], backView = nil;
    }
}
 
- (UIView*)backView
{
    if (backView == nil)
    {
        self.backView = [[[UIImageView alloc] initWithFrame:...] autorelease];
        backView.image = [UIImage imageNamed:@"Some Image"];
        [self.view addSubview:backView];
    }
    return backView;
}
 
- (void)showBack
{
    self.backView.hidden = NO;
}
 
@end

Now whenever I need to use the back view, I access it with “self.backView”. If it’s not yet loaded, it will be constructed right then and there. So we can safely release it in -didReceiveMemoryWarning if we’re not using it, and it will come back to life when we do want to use it again.

UIImage imageNamed

You probably load your images using the -[UIImage imageNamed] method. It caches the images behind the scenes. There once was a time where -imageNamed did not properly release the cached images on a low memory warning but apparently it has been behaving well for quite some time now. Unless you’re still targeting 2.x, I wouldn’t worry about it.

But if you don’t trust -imageNamed‘s caching mechanism or want more control over it, you can create a simple image cache of your own. Something like this:

@implementation MyImageCache
 
+ sharedInstance
{
    static MyImageCache* instance = nil;
    if (instance == nil)
        instance = [[self alloc] init];
    return instance;
}
 
- (NSMutableDictionary*)dictionary
{
    if (dictionary == nil)
        dictionary = [[NSMutableDictionary dictionaryWithCapacity:10] retain];
    return dictionary;
}
 
- (void)dealloc
{
    [dictionary release];
    [super dealloc];
}
 
- (UIImage*)imageNamed:(NSString*)filename
{
    UIImage* image = [self.dictionary objectForKey:filename];
    if (image != nil)
        return image;
 
    image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
    if (image == nil)
        return nil;
 
    [self.dictionary setObject:image forKey:filename];
    return image;
}
 
- (void)flushMemory
{
    [dictionary release], dictionary = nil;
}
 
@end

This will keep images in memory until you tell the cache to flush itself. You’d typically do that in your app delegate’s -applicationDidReceiveMemoryWarning method. Note that it loads the dictionary lazily, so no memory is wasted if you don’t use the cache.

A cache like this is useful for buttons or other controls whose state can change. A “Play” button might change into a “Stop” button while the sound is playing. If memory gets low, you can release the “Play” image. The “Stop” image will also be flushed from the cache, but the UIButton will still hold onto it as it is currently displaying this image. When you switch back to the “Play” state, the old Stop image gets freed and a new Play image is loaded into the cache.

Test in the simulator

The iOS Simulator has a menu command that lets you fake low memory conditions: Hardware > Simulate Memory Warning. This is mandatory for testing whether your code actually works! Use this and the Allocations instrument from Instruments to make sure your app can survive when it runs out of memory.

I haven’t found a way yet to trigger low memory conditions on the actual device, other than allocating big chunks of memory with malloc().

Want to make a game? Build a prototype!

On sites such as Elance, I often see job listings for games. Here is a tip if you’re considering having a game developed: first hire a developer to make a prototype to see if it’s worth investing in building the full game.

Let there be no mistake about it, making a game is a lot of hard work. There is a ton of design, programming, graphics, sound effects, music, testing, tweaking and polishing that needs to be done. It will take months. And the kicker is, you won’t know if the game is any fun until it’s nearly finished.

That’s a big gamble to take. If the game turns out not to be any fun, chances are it won’t sell very well and you’ve just wasted a lot of time and money on a dead product. Unfortunately, it’s impossible to predict whether the gameplay will be any fun until you can actually play the game.

Play your game as soon as possible

There is a smarter way. First build a prototype in order to test out the gameplay mechanics. The prototype has only one purpose, to learn whether the gameplay idea works. Is it possible? Is it fun? And we want to find this out as quickly as possible.

You can do a lot of the prototyping yourself long before you set out to hire a developer. Start with pen and paper, cut the game pieces out of cardboard, get some friends together and try it out. A lot of games can actually be prototyped this way. You get to do beta testing before a single line of code has been written.

If your paper prototype works, there still is no guarantee the idea can be transferred to a computer game. The next step is to hire a developer to convert your paper game into software.

Prototypes are messy

The keywords to making a software prototype are “quick and dirty”. It will use ugly placeholder graphics, there is often no sound or just very basic bleeps, the game won’t have much of a menu structure, the source code will be awful. It also requires a bit of imagination to see how it will end up being the final game. But none of that matters: the only purpose of the prototype is to tell you whether the gameplay mechanics will work.

Here is an example of such as prototype:

This is a block-stacking game idea I had a few months back. You have to rearrange the blocks into a tower by dragging and/or rotating them, so that the cute creatures (the red circles) can reach the exits. Not a bad idea, except for one thing: it doesn’t really work well on the iPhone. Your fingers obscure too much of the playing field, so it’s hard to see what you’re doing. Only a prototype will tell you those things!

It took me a few evenings to put this together. I hacked it out as quickly as I could, cutting corners where possible. As you can see, it’s not very pretty. Simple colored blocks represent the game characters. There’s no point in making beautiful artwork if you don’t know yet whether the game is worth building.

Unfortunately for me, the game idea did not turn out to be viable. Well, that’s how it goes. It’s better to know that sooner rather than later.

Prototype, tweak, repeat

If the prototype just isn’t any fun to play — and often the very first version isn’t — then you can tweak it. At this point, changes to the gameplay rules are cheap and easy. You don’t have to throw away expensive artwork, because you didn’t create any yet.

Early in the project is the best time to make big changes. Major modifications to something as fundamental as the game idea will become much more expensive as the project goes on. If the changes end up being way outside of the project scope, it may mean having to renegotiate with your developer. It means throwing away artwork you’ve already paid for and having to pay for new artwork. In any case, it will cost you.

Throw away the prototype

If your game idea works, that is wonderful. Now throw away the prototype and start over from scratch. Prototype code is meant for throwing away, not for publishing. Don’t feel like you have to use this code because you paid someone to write it. What you paid for was the validation of your idea, nothing more.

You don’t want to build the final product on a code base that was slapped together as quickly as possible. Instead, give the developer the freedom to go back to square one and build a proper foundation for the game.

Writing the prototype should already have given the developer a better idea of how to structure the code properly, because he understands the underlying problems now (he already solved them once). As software project management guru Fred Brooks says, “Build one to throw away.”

Reduce your risk

To summarize: first hire a developer to build a prototype, work through several iterations until you are sure that either: a) The game is fun and it’s worth doing it for real, or b) The game just doesn’t work and it’s time to drop the idea and move on to the next.

Certainly, getting a prototype built is a lot cheaper than getting the full game developed. The software business is risky; use prototypes to reduce your risk.

By the way, this goes for apps too. If you’re unsure about the best approach to your app — and this is something I see on a regular basis — then get a prototype done. In fact, that is how I usually treat the first milestone of any client work I do.