PhotoTangler was my first iPhone app. My programming background has largely been in 3d video games and simulation, primarily on the Windows platform. I’ve been using a variety of other platforms for quite a while (including Linux and Mac), but most of my serious development projects had been on the Windows side. To learn about iOS development, I spent a week consuming two iPhone books (and Apple’s documentation), then got to work on my app idea.
When I began the project, I had to make a few decisions about what versions of iOS to support. For example if I used OpenGL ES 2.x, my app would only work on the iPhone 3GS or later. It so happened I had one of the very first iPhones (Edge, 4GB) lying around, so I decided to test its capabilities. After a quick prototype, I concluded that ES 1.x could do all i needed, meaning I could support any iPhone out there. My strategy was then to do all development on this ancient phone, expecting that if it ran well on this bad boy, it’d run like a dream on newer phones. This is something I used to do in games– write stuff on older machines, with older graphics cards– with hopes it’d run well on the newer stuff. And it usually worked great. Turns out that for the iPhone, that just wasn’t the case.
I wrote and tested the app on the aforementioned phone, as well as an iPhone 3G that a friend gave me. By the time it was finished, everything worked perfectly. I hammered it with a pretty rigorous combination of test runs each time I did a build, and it never crashed. It seemed rock solid. I sent it to a handful of friends for testing, and they reported good things. So I published it.
For the most part, I considered the launch a success. People seemed able to run it, and it was selling better than I expected. But I kept receiving sporadic reports (or the occasional negative review) about the app crashing. I followed up with anyone I could, trying to get the steps to reproduce it, but I simply could not get it to crash on my old iPhones… ever! The whole time I kept thinking “if it runs on this old thing, it should run on anything!”
The turning point came when something strange happened with the App store. I pushed a new version (1.1) of the app to Apple for review, and the full version was accepted– but the Lite version was rejected due to crashing. This was odd because they were the exact same code with a few #defines to limit the number of images the Lite version can import. I had to figure it out. The crash report they sent was from an iPhone 4, matching my growing suspicion that crashes were only happening on the newer phones. I bit the bullet and bought an iPhone 4, hoping I could find a way to reproduce the crash (after playing all the latest 3d games of course!) Turns out, I could. First try.
As most developers know, being able to reproduce bugs is typically the hard part. Once I was able to, fixing them was simple. But crashes aside, I was kind of shocked at how many differences I noticed in the way my app looked and ran on the iPhone 4 compared to my other phones. It took barely an afternoon to fix all of the issues I found. Most were related to what happened when memory warnings occurred if a lot of apps were open simultaneously, which explains why it didn’t crash for all iPhone 4 users. Since 1.2 of the app was released, I haven’t received a single crash report. Knock on wood!
Overall, I suppose I’d expected a greater degree of backwards compatibility as I’d been used to with most other SDKs I’ve used. I learned the hard way that deprecated on iOS really means deprecated. Of course I take full responsibility for the quirks that were in my code. But I wrote all this both to remind myself, and to caution others (with limited access to devices) against using a similar development strategy. Expecting an older baseline to provide maximum compatibility didn’t work well for me, though I also don’t know that it would’ve worked any better the other way around. Moral of the story? Assume nothing. Test everywhere. Best of luck.
Posted under: Technology, on April 9, 2011.