SwipeHead
Most of us, at some point, will apply a label of sorts to ourselves. Are we teachers, rocket surgeons, hippies, nihilists, or maybe middle-aged? A single label rarely suffices, and I’ve gone through a few myself. I’ve alleged myself to be a musician, a coder, a technician, a writer (hah), and had a few other stints. There’s a common thread here: I like making things. With that out of the way, in the middle of December I helped to make this:
This is SwipeHead, a sort of hybrid puzzle game for the iPhone and iPod touch. I’d explain how it works, but figuring that out is one of the more satisfying puzzles. It reminds me a bit of old LucasArts adventure games in which a challenge would be posed and various tools offered, but after that it was up to the player and their wits. SwipeHead, likewise, is meant to have an intuitive learning curve and once it gets going, is very enjoyable.
Though I might seem to be trumpeting my own horn, the real kudos go to the game designer, Leanne, over at Wizkeit Games, who designed and produced the whole thing. For my own part, it’s humbling to see my code executing on other devices and available on the iTunes Store. I know there iTunes Store is a pretty saturated market these days, but it doesn’t detract one bit from the glee. More horn trumpeting yet: it was accepted on the first submission, which Leanne and I were told doesn’t happen often.
If you’re looking for a unique experience among the many app clones on the iTunes Store, give SwipeHead a try. When I first saw the design documents, it wasn’t one bit like any other puzzle game I saw out there, and remains so even post-release. Though only a mere $0.99, there’s a free version as well to whet your appetite.
[UIImage imageNamed:]
UIImage *myImage = [UIImage imageNamed:@"pony.png"];
This is probably one of the most convenient methods I’ve ever come across. Feed it a name and it will return an image. Better yet, it handles caching for you automatically so that you don’t have to. Notice something about it though? There’s no alloc, meaning you shouldn’t call release. If you can’t call release, how do you get your memory back? This isn’t a big deal when using Mac OS X’s older brother, NSImage, since your average computer these days ships with several gigabytes of memory as opposed to the paltry 25MB or so that most iPhone apps are limited to. If you’re dealing with a lot of images on the iPhone though, this hands-off caching approach is going to cause problems.
The first obvious solution is to just avoid the convenience method and manually alloc and load each image with its full path:
UIImage *myImg = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/pony.png", [[NSBundle mainBundle] bundlePath]]];
That’s not awful for loading an image or two, but if you’re going to load many images, why not encapsulate this in something more elegant? Since such a method would be useful application-wide, it furthermore makes sense for the method to exist in its own application-wide class, rather than just stuffing the method willy-nilly into whatever class you’re working in. Actually, if you’re going to go to the trouble of creating a new class just for a convenience method, why not make it do other neat things? Let’s do that.
OpenGL ES from the Ground Up
Back in developer land, I’ve found something terribly interesting. A fellow by the name of Jeff Lamarche has written up an OpenGL ES tutorial geared towards iPhone Devs. OpenGL has always terrified me, so this will be a great resource. Better yet, OpenGL, as hinted by the word “open,” is intended to be a very portable cross-platform tool, so the lessons learned should be equally portable.
Object Chains
This almost certainly isn’t a first, but I discovered a neato trick. Let’s make a chainable class, called Chain. It would contain two instance variables (at least) called next and previous, also of the Chain class. Its init method would go something like this:
- (id)initChainOf:(int)n
{
if(self = [super init])
{
// Setup instance variables, etc. Then:
n--;
if(n > 0)
{
next = [[Chain alloc] initChainOf:n];
next.previous = self;
}
else
{
next = NULL;
}
previous = NULL;
}
return self;
}
Call Chain *myNewChain = [[Chain alloc] initChainOf:5]; and you’ve got five new objects linked together. After the first object is initialized, it decrement the link number and initialize another link if the link number is above zero. The next link repeats the process until the link number reaches zero. The instance variable previous (more explicitly called self.previous) is initially set to NULL, but if the link has been created by a parent link, it will manually set next.previous to self, which alone is a slightly confusing statement. Clean up works similarly:
- (void)releaseLink
{
if(next)
{
[next releaseLink];
[next release];
}
}
One link will call the next to release its link, which will then call to release its next link, etc. No object actually releases the self.next object until it has told its own link to do the same, so all the releases actually cascade down. The whole thing can be unravelled with two lines:
[myNewChain releaseLink]; [myNewChain release];
Recursive programming is one of those things that’s crude is misused but elegant when done right. I’m not sure which the category the above falls under, but maybe it’s too bare bones to qualify yet. With the above setup, you lose some of the control that NSArray and its mutable counterpart provide. On the other hand, it’s probably leaner and faster at what it does if you don’t need all that control. Sorting is non-existent, inserting objects between links (or inserting any object at all that isn’t a Chain) becomes problematic, but its behaviour is just what I need right now.
Instruments: Building a Watertight App
Probably one of the main criticisms I’ve hear about iPhone applications is that they have a tendency to crash. This is not isolated just to bad applications, not that it helps. If I had to make a wild guess, I’d say the main cause of such crashes is memory leakage combined with the iPhone’s apparent 128MB of memory. Sure, on a desktop with several gigabytes kicking around, you could almost afford a few sloppy leaks (not that you should), but the iPhone offers no such padding. You don’t need a big leak either as long as it keeps growing; add to this that many non-Mac developers have no previous exposure to Cocoa’s alloc-retain-release methods and you’ve got an application ready to tank.
Instruments, part of the developer tools, has a crazily useful module called Leaks that does exactly what it advertises. It keeps track of all memory allocations and deallocations and lets you know where the outstanding balance is and which method it lives in. Although early optimization is considered be on par with supervillainy, leak detection is not optimization per se and I would recommend profiling for it early and regularly. Method calls will only get deeper and more tangled as time goes on. I was surprised to learn that my own code had nine leaks, nine. That’s nine more than I was hoping for. I’ve cut it down to a single 3.5KB leak thanks to Instruments, and while that may not seem like much, I’m going to find and nuke that 3.5KB before the night is over.
Mirror, flip, inverse, invert, stop drop and roll
Not having much to compare it to, I can’t honestly say how well the developer documentation stacks up against those available on other platforms. It certainly serves me well enough, and is worlds apart from what came with MPW. The day that MPW finally started working was a small miracle; this was before Google had an answer to just about everything (great instructional video too), and most libraries assumed you were using CodeWarrior anyway. At any rate, the reason for today’s post: for everything not spelled out by the developer docs, there’s Google.
After spending a good hour trying to trackdown a [UIImage reverse] method (there is none), I’ve boiled it down to a working block of code. Best of all, it’s short! So here’s to you, Googlers, I’m putting it on the internet in hopes that another dev finds it useful. The following snippet will horizontally reverse/flip/mirror a UIImageView:
UIImageView *myView = [[UIImageView alloc] initWithImage:myImage]; myView.transform = CGAffineTransformIdentity; myView.transform = CGAffineTransformMakeScale(-1.0, 1.0);
That’s it. To flip it back:
myView.transform = CGAffineTransformIdentity;
Not so scary anymore! So what’s going on here? Get your answers from a more authoritative source. It’s a good read about a powerful property, and highly recommended for anyone who doesn’t want to create two or ten different versions of the same image at different rotations.
Breakin’ Stuff
It’s 6am and sleep is proving impossible. My brain won’t shut down, instead thinking about the enormous possibilities made available by the iPhone SDK. Objective-C is back with a vengeance; as is becoming the norm, the main() function is meant to be off-limits, and there isn’t really a substitute for it either. Instead of being a hindrance, it’s a godsend. Draw up an interface, plug in some code, connect the outlets, and bampf. Classes start talking to one another. Instead of growing an increasingly crazy tree of functions pushing values up and down, there’s actually some kind of programmatic dialogue going on. While this probably isn’t a new concept to an experienced programmer, it’s the first times that I’ve found it intuitive.
Anyway, that’s just it. The whole thing has me pretty excited and the brain won’t pipe down, instead busying itself by dreaming up ways to keep classes nicely self-contained and autonomous while actively participating in the overall program. Or, maybe a way to make views handle themselves and report when something important happens, instead of controllers polling them constantly when resources could be better spent.
Not that it’s all unicorns and rainbows. Registering, configuring, and provisioning a test device was like finding out the rainbow is made of sewage, and the unicorn just ate your last pie. You eventually work through it, but probably won’t look forward to doing it a second time.
