Project Organization and Coding Conventions for iPhone Games
Now that we’re knee deep in iPhone game development, we’re working with a number of different outside developers. Since everyone involved is pretty new to Objective-C, XCode and iPhone development, project organization and coding conventions in our projects have been all over the map. To improve the quality of our projects and make them easier to maintain and update, here’s a list of things to keep in mind when developing casual games for the iPhone. Most of them are common sense, but going back to basics every now and then never hurts.
- Remember that somebody else (who may not know all the ins and outs of XCode) will be working on the project with you. Take the time to keep things neat and organized. Create a Classes folder with all your source code and a Resources folder with nib files, images, sounds, etc. Keep the organization of the project and the organization of the files on disk as close as possible, it’s less confusing for everyone. Give all of your files consistent descriptive names. Delete files that aren’t being used anymore (Tip: Make bundles for any resources that don’t need to be compiled, like images and sounds. XCode doesn’t keep track of the contents of bundle files, which means when you add/remove/rename files in the bundle XCode will automatically see the changes so you don’t have to remember to add and remove them from the project). Simple stuff, but it makes a big difference.
- Pushing updates to the App Store is a proven way of improving a game’s visibility, so make sure the project and the code are easy to update. Remember to slow down and do things well.
- Use Foundation and UIKit classes wherever possible — it helps keep user interface elements consistent and it’s easy for another developer to quickly see what’s going on and make changes without learning another 3rd party framework. For example, use a UIView with UIButtons for game screens. The exception to the rule here is the game engine itself, where the benefits of using OpenGL or other open source code are worth the trouble.
- Use Interface Builder wherever possible — this goes hand-in-hand with the last point. Using UIKit classes and Interface Builder makes it easy to adjust the layout of screens, labels for buttons, etc. without hunting through the code. Remember, the person making the adjustments may not be a programmer.
- Use UILabels for interface text, rather than embedding text in images. Keeping text out of images makes the project much easier to update and localize. Using native text for everything also helps keep things consistent visually – your high score screen is going to need dynamic text and the app will look better if it matches everything else.
- Memory management is very high priority on the iPhone. Use as little memory as possible. Don’t load things into memory until you need them. Release things from memory when you’re done with them. For example, rather than loading all of a games screens when the app launches and keeping them in memory for the life of the app, load each screen when it’s going to be shown and release it from memory after it’s hidden.
- Test the app regularly in Instruments during development to find memory leaks and avoid wasting memory:
- Check using Leaks — This will help you find good, old-fashioned memory leaks.
- Check using Object Allocations — An object in memory may not technically be a leak, but if it doesn’t need to be there it’s wasted memory. When you’re playing the game, are any of the objects associated with the other screens in memory? When you’re showing the game over screen, are any of the objects associated with the game engine in memory?
- Check using Memory Monitor — Apple doesn’t specify a hard limit on the amount of memory an app can use, but the general consensus is that 15Mb to 20Mb is fairly safe. If your app is using 25Mb of memory you should be concerned. If your app is using 45Mb of memory you have a very big problem.
- Check OpenGL Texture Memory — OpenGL on the iPhone has a soft limit of 24Mb for all textures. If you go above the limit, there’s a massive performance hit. See: How To Check iPhone Texture Memory Usage With Instruments
- Follow standard Objective-C naming conventions. They’re different from other languages, so take the time to read up on them. See: Coding Guidelines for Cocoa, Cocoa Style for Objective-C: Part I, Cocoa Style for Objective-C: Part II
- Put the
deallocmethod at the top of the@implementationblock for every class you write.deallocis the most important method in every class, so show it some love. - Use accessor methods for everything — it’s the best way to avoid simple memory management bugs. Use accessor methods within classes, too. You can define private accessor methods in a category at the top of your implementation file. You can redefine a readonly property in the public interface as a readwrite property in the private category.
- Mark properties as
nonatomicunless you have a good reason not to. - Use square bracket syntax (i.e.
[self foo],[self setFoo:@"bar"]) instead of dot syntax (i.e.self.foo,self.foo = @"bar") for accessing properties. Using one syntax keeps your code consistent, and makes it easier to see where you’re accessing a property of an Objective-C object as opposed to a member of a C struct or C++ class (which use dot notation). - Avoid subclassing UIViews. Build the view hierarchy in Interface Builder and put your logic in a UIViewController. If you have a lot of UIView subclasses, you should be concerned.
- Remember to mark properties as
IBOutlets and methods asIBActions wherever it makes sense. - Organize related methods and properties into groups in the source code (i.e. the UIViewController subclass for a game screen might have groups like button properties, action methods and overridden UIViewController methods). Mark the groups in both the header and the implementation using
#pragma mark Label. Organize methods within a group alphabetically. You’ll spend a bit of time organizing things and a lot less time looking for things. - Use
NSAssert()liberally. If you intentionally stop the app when something unexpected occurs, it’s easier to find where the problem started and fix it. It takes a bit of time to write the assertions, but I guarantee it takes less time than tracking down a bug later on.
The list above is by no means definitive, but it covers the basics. Let me know if I’ve left out anything obvious, or if there’s something that rubs you the wrong way. I’m always happy to learn a better way to do something.
June 9th, 2009 at 10:52 am
hello,
this list of thoughts (while may seem pretty standard from any development standpoint) is very nice to see… so, thanks for posting it!
i am a traditional flash developer but have recently (past few years) been into coding in OO languages like java and the more recent versions of actionscript which is OO based. where should i go for syntax standards so this language is more readable to me? with the basics of syntax, i think i could be up and going pretty quickly. any help on that topic would be greatly appreciated and certainly get me writing code for the iphone in the proper format.
-aj