views:

165

answers:

1

Background:

I have a tableview displaying about 8 sections each backed with my own PlaceList class representing a list of objects (the implementation uses an NSMutableArray). There are around 200 objects in total. Each section corresponds to how far away the object is from the current location (e.g. within 1 mile, within 10, 25, 50...etc).

Every now and then, I need to respond to asynchronous notifications from CoreLocation that require me to recalculate which section each object belongs in, update the distance for each object (which is displayed in each cell), and also resort each list, then reload the table view. I also do this operation in viewWillAppear.

Within the operation that performs the update (a method on PlaceList) I've used @synchronized(self) in case it gets invoked from more than one thread by the OS (I don't use another thread for it myself at present). However, currently this operation results in the UI feeling 'frozen' from time to time, so I'm looking at ways to do it in its own thread.

Question:

  • What's the best way to do this kind of long running operation on the data backing a table view? As far as I can see it is not safe to spin off a background thread to do the operation, as even if I use performSelector to reload the table view on the main thread when done, it is still possible that the user will tap a cell while the operation is running and the data is not consistent with the display. And adding any kind of locking would just defeat the purpose.

  • Do the UI and CoreLocation locationManager send their notifications on the same thread, i.e. can I safely dispense with the @synchronized(self) on the PlaceList?

+2  A: 

Here's my understanding of your problem. You have a large list of data, and at some point it will become invalid. In order to get it valid again, you have to do some processing before you can repaint the table.

If this is correct, here's a few options.

1) Double buffer your data. As long as you are displaying something that "was" correct, the user can interact with it just fine. When you get your trigger to reprocess your data, work on it in the background with a copy, and when it's ready to redraw completely, update. That update may be abrupt and large, but the data displayed will always be correct, or at least sane, and the UI continues to function and doesn't scare the user.

This largely avoids the threading issue since the notifications aren't modifying data and trying to show it at the same time.

AFAIK, the Facebook application seems to do this, as well as TwitterFon. At least that's how it feels. Hard to say for sure.

2) Loading screen! Not fun, but it works. When you know the data is bad, throw up a semitransparent panel and tell the user to hang on a bit.

It really boils down to update now, or later. You have to decide what trade-offs make the most sense in your application.

Nick Veys
Have tried the loading screen option, but I think I will give option 1 a go, perhaps using an NSOperationQueue to start the update on a worker thread. The drawback is that the update is potentially very large from time to time (i.e. stuff moving between sections), which might be weird for the user. I wonder if tableview can be made animate that.
frankodwyer