SeattleBus Diary: One thousand eighteen bus stops

One thousand eighteen bus stops

… or how [UITableView reloadData] kicked my butt

The SeattleBus application includes a database with 1018 stops in it. Those were all the stops that I had with geolocation data and to which the MyBus web service responded with stop information. I started with 1211 data points, but just around 15% of the bus stops didn’t return any data.

One of the views in SeattleBus is a list of all the stops – and that’s where I felt the pain. In fact, it wasn’t until after 1.0 shipped that I realized exactly where the pain was coming from. It isn’t interesting caching or slow lookups from SQLite – it was from invoking UITableView reloadData where the data had 1000+ elements. Loading 100 or even 300 was a pretty reasonable delay. You’d notice it, but it wasn’t too bad. 1000 just pushed it over the edge to a good few seconds. Not to mention the UI component of trying to scroll through 1000 items on the iPhone. Man, that’s just painful. It screamed for (and I implemented) a search mechanism to make it a more useful view.

At WWDC this year, they warned us that reloadData was expensive. Ooooh yeah. One of the suggestions that I heard for resolving that was to load a subset of the data (say 100 rows, which isn’t too bad of a wait) and then using the method UITableView insertRowsAtIndexPaths:withRowAnimation: to inject additional rows using a background thread of when the user gets to where they need them. When I’d do a search and get back anywhere from 8 to 100 items (typical search in my tests), the reload was nicely fast. It was when I cancelled the search and reloaded the original view that everything went to hell. After reseting my model objects like a good programmer, I’d invoke [UITableView reloadData] like I was used to doing on a desktop Mac’s NSTableView. Then (on the device – the simulator was plenty fast), I’d wait.

Kris Markel came up with an interesting solution when cobbling together a search example for me (now That’s a beta tester!). Instead of preloading the data he was loading it in from the database in the UITableView data source method tableView:cellForRowAtIndexPath:. Ahhhh, right. I didn’t follow that path exactly (although I was darned tempted to), but instead implemented caching so that once I did that particular load, I didn’t have to re-do it again and again. I’ve got the application set to blow that cache away on a low memory warning, but it’s made a lot difference.

The next step there will be to load a subset up front and then populate that cache in the background with NSOperation or something equally interesting for a background thread. There’s no reason the user should have to wait through the 2.7 seconds of loading time for the whole kit.

3 thoughts on “SeattleBus Diary: One thousand eighteen bus stops

  1. I’ve been fighting my own similar performance battle lately, so this was extremely helpful reading! Sometimes I think we desktop Mac developers are actually at a disadvantage in the iPhone world, since we’re so accustomed to the normal “right” way to do things. Thanks for writing that up, Joe!


    • All props go to Kris Markel on this one – he’s the one who I first heard the solution from. I was more than happy to write it up – I figured someone else would run into the same issue I did. Glad it was useful!


Comments are closed.