Web Development

Developing for the iPad

By Jonathan Branam, April 16, 2010

Ideate is an iPad app for turning ideas into products

Custom Controls, Forget Interface Builder

Our first design for Ideate included several custom controls. In particular, we did not use the standard that anchors to the top or bottom of the window; instead we designed a menu that collapsed into itself to give the user the entire screen to use as a sketching canvas. Laying out a standard UIToolbar is very easy using the Interface Builder application. It is trivial to drag a new UIToolbar into the XIB and then drag buttons, flexible space and fixed space UIButtonBarItems onto it. Being new to the iPhone SDK, I spent a lot of time trying to get our custom menu to work the same way inside of Interface Builder.

I ran into numerous problems with this approach because to hide the buttons when the menu collapsed, I found it necessary to add a UIView into the view hierarchy inside the menu but above the buttons. When I tried to do this in my code I lost the button layout from Interface Builder; when I did this in Interface Builder it created a hierarchy that was very difficult to navigate. My solution was further frustrated by losing the nice layout options in the UIToolbar and being forced to use absolute positioning to align my buttons. The last frustration was that my custom views in Interface Builder rendered as white (since they were drawn in code) and my buttons were only white text against the background, so they were all invisible in Interface Builder until clicked on.

My final determination was that Interface Builder is not the tool for laying out highly custom user interface elements. In the end, working on the custom menu took too much time away from more crucial development tasks so we returned to using standard UIToolbar menus. Using the standard menu also helps Ideate look like other iPad applications and helps the user know what to expect from the toolbar. We also used Interface Builder for building our popups since they used standard UI elements.

Later in the project, we implemented a custom tool tray. For the tool tray we did not make use of Interface Builder, but instead built it all in code. This approach was appropriate for the task. In Figure 3, you can see the brush edit popup that is built in Interface Builder, and the tool tray on the left which is all built in code.

Figure 3

Save Fast and Save Often

The concept of continuous, incremental saving is crucial to the operation of every iPhone OS application. Users on the phone may be interrupted at any time to receive a call and may decide to exit your application at any time. Apple frowns on applications that offer an explicit Save or Load button, instead encouraging developers to save while the user works. For Ideate, I designed a custom file format based on the PNG image file format. The PNG format supports custom chunks in the file which can contain any data that an application required. Adobe Fireworks uses this approach to store all of its metadata in a PNG file and I thought it was a good idea. This means that browsers, image editors, and mail clients can all render an Ideate image, but only the Ideate app itself will load and save the custom chunks of data inside the file.

I chose the libpng library to implement this solution since it is widely used and supported across many platforms. I also found references to developers using it successfully in existing iPhone applications. After some frustrations getting libpng compiled for both ARM and i386 for use in the iPhone Simulator and on the device, things seemed to progress well. I implemented an initial approach which stopped everything to save the sketch to disk. This was clearly not ideal, so I later moved the saving code to a background thread to keep the application responsive. For safety, I used a locking mechanism on both threads so that the saved sketch would always be consistent. I declared a lock object inside my Sketch model object like this:

NSRecursiveLock *sketchLock;

I then wrapped every operation that changed the state of the sketch in a pair of lock and unlock messages:

The save operation was also wrapped in lock/unlock pairs so that it would be an atomic operation. I then ran a timer which would save the sketch every 15 seconds if it changed, and also implemented a call to save when the application terminated. All of this seemed like a great solution and it worked perfectly in the simulator. There was very little interruption during saving and the saving and loading appeared robust. However, I was in for a surprise when I first got an iPad and was able to use our application on it.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!