Adam Ernst
Adam Ernst

Reputation: 54060

Threadsafe UITableView

I'm using a UITableView to show some data from an array. This array can be changed at any time by other threads. (I believe that whether the array is mutable, or just replaced entirely, doesn't make a difference.) Access to the array itself is threadsafe.

What's the proper way to ensure thread safety with regard to the tableview? I'm worried, for example, that I might change the array to be shorter just before cellForRowAtIndexPath is called, leading to an NSRangeException.

Should I...

  1. Enforce that the array is only changed on the main thread? (Seems ugly.)
  2. Maintain a shadow array and update this on the main thread through KVO observing?
  3. ??? There must be a better solution...

Upvotes: 4

Views: 1936

Answers (3)

Jon Shier
Jon Shier

Reputation: 12770

Without knowing more about your app, I think one of the better solutions would be to keep the array on the main thread and dispatch back to it whenever another thread needs to make a change. Like this:

dispatch_async(dispatch_get_main_queue(), ^{
                [array addObject:object];
                [tableView reloadData];
            });

Of course, you can get much more complex with the dispatch API, but it does handle locking and everything for you. Definitely more elegant than using an NSLock. It does only work on iOS 4 or later though.

Upvotes: 3

Oscar
Oscar

Reputation: 2345

I have the same situation. I have an array of C++ objects that provide the info in the tableview.

As Ben referred to, I also have a temporary "shadow" array into which new information is downloaded over the Internet. When the query is complete, I reconcile that array with the one backing the tableview, which is quite fast. The question is how to protect the array during that reconciliation.

I'm doing the reconciliation on the main thread, but I'm not sure that's sufficient to protect from conflicts, especially if the user taps on an entry while there's a query pending; the underlying object he's viewing details for might be blown away.

There's a similar question to yours (and mine) here: Update UITableView using threads

but the answers berate the poster for taking too long with his background operation, instead of answering his question.

I'm going to use an NSLock, and acquire it before altering the array and in all of the UITableView delegate methods, unless somebody has a better idea.

Upvotes: 1

Ben Gottlieb
Ben Gottlieb

Reputation: 85532

From your description, you really have TWO different data sets:

  • The actual data, as it exists in your model
  • The data that's displayed to the user

Thus, you already have, in effect, a 'shadow' array (virtual shadow, which may be stretching the metaphor too far). I'd say your best bet is to formalize this arrangement, and keep a 'display' array that only gets modified in the main thread. In it, you can have objects from your 'real' array; since they're only pointers, you won't be giving up too much memory.

Threading is evil.

Upvotes: 6

Related Questions