views:

1130

answers:

2

Hi all,

I currently have one UITableViewController that contains many cells with simple data in it. When the UITableViewController instantiates a UITableViewCell, it begins running a background thread for each individual cell to get its state from the server. The UITableViewCell is subclassed and already has a UIImageView property that needs to get added to the contentView once the data from the server is ready.

My problem is that is that I need to call [tableView reloadData] everytime I get new data back from the background threads. This is a bit overkill, as I can simply add the UIImageView to the contentView by accessing the affected cell directly. I'm just not sure of the best way to find the cell for when my data management utility is done doing its work (speaking to the server).

Does it make sense to do something such as passing the indexPath of the cell when calling my data manager to run its background task and then passing that indexPath back when the task is done? Is that overkill?

What's your favorite way for handling this common task?

Thanks SO crew.

+3  A: 

In the case where the data needs to change inside of the cells I do not use the dequeueReusableCellWithIdentifier:(NSString *)identifier method. That stops the UITableView from caching the cell. When table view cells scroll off of the screen they are released. There is a delegate method,

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

that gets called just before your cell will be drawn. You can use this to, yes pass the indexPath to the manager.

When your data comes back, I usually call the method

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

to get the cell, then set the text in the cell and call its UIView superclass method, - (void)setNeedsLayout.
That will tell the cell to redraw.

Another way I have done it is to use a custom cell, and have that custom cell subclass call the manager for its data directly when it is drawn. When the data comes back, it calls a custom delegate method on itself to update its internal UILabel objects and then calls setNeedsLayout.

Heat Miser
A: 

If you don't mind having a placeholder in your cell while the image loads, you can use something like TTImageView in the Three20 library. The image view is always in the cell and you specify its image URL. The image view handles the URL request, and when the image is loaded, it's automatically displayed.

While I don't use Three20, I do something very similar in my code. This is compatible with table cell reuse identifiers -- when a cell scrolls off the screen, its image view URL is changed to a new value, which cancels the URL request (if it's still ongoing) and starts a new one. Combined with caching, when you scroll back up the image will load instantaneously.

Daniel Dickison
Daniel -- that works. My problem is, I already have the image. I just need to retrieve more information from the model which resides on the server. So, I'm torn with whether or not I should leave the logic in the cell subclass itself, or within the dequeue process.
@Steve - if the additional data ends up changing the cell height, then you'll need to do a full table view reload anyways. Otherwise, I would make your cell a delegate of the data fetching requests; something like dataRequest:receivedData:
Daniel Dickison