Reputation: 4657
I have a custom UITableViewCell
where I set the image in a UIImageView
from an URL using AFNetworking
. When the image is loaded I want to resize the image view and the cell in order to fit the image.
In my tableView:cellForRowAtIndexPath:
I have the following code:
FeedItem *feedItem = self.dataArray[indexPath.row];
FeedItemCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"FeedItemCell" forIndexPath:indexPath];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:feedItem.thumbnailUrl];
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
[cell.thumbnailImageView setImageWithURLRequest:request placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
cell.thumbnailImageView.image = image;
// first I set the height of the image view
cell.thumbnailImageHeightConstraint.constant = image.size.height;
// then I save the height in a dictionary to return it in tableView:heightForRowAtIndexPath:
[thumbnailHeights setObject:[NSNumber numberWithFloat:thumbnailHeight] forKey:[NSNumber numberWithInteger:indexPath.row]];
// now I reload the cell in order to have the new height applied
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"failed loading: %@", error);
}];
In my tableView:heightForRowAtIndexPath:
I have this:
NSNumber *thumbnailHeightNumber = [thumbnailHeights objectForKey:[NSNumber numberWithInteger:indexPath.row]];
if (thumbnailHeightNumber != nil) { // image size has been calculated
return thumbnailHeightNumber.floatValue;
}
return 0;
This sort of works. The height is set correctly on both the image view and the cell. However, there is some unpredictable behaviour:
tableView:cellForRowAtIndexPath:
is correct, but it displays content from one of the previous cells.I have noticed something that might be related to the issue. My tableView:cellForRowAtIndexPath:
method is always called twice, which I believe is actually causing my problems. If I remove the line [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
it is only called once (for each row) and the problems stop, but of course then the height of the cell is not updated.
Also, I do not believe that the issue is related to the actual change in the cell height. If I set a fixed height for the image and the cell height, I still get the same side-effects when calling reloadRowsAtIndexPaths:withRowAnimation:
.
So I am hoping that there is either a fix for this issue, or some other way of accomplishing my goal of dynamic cell height.
Upvotes: 1
Views: 567
Reputation: 4529
The call to setImageWithURLRequest:request:placeholderImage:success:failure:
is asynchronous, so cell.thumbnailImageView
is going to be unpopulated or (if the cell is being re-used) have previous image data in it until setImageWithURLRequest
succeeds, probably some time after tableView:cellForRowAtIndexPath:
has already returned the cell. If setImageWithURLRequest
fails, then your cell is left with an unchanged/unconfigured thumbnail image view.
You can provide an image in the placeholder:
argument which will be displayed until the success
block is called, then at least you also have a fallback for the failure case.
The table is likely to flash as the various cells' success blocks get called asynchronously some time later, each of them forcing a reload of different rows.
Unless you know the thumbnail images are all a fixed size in advance (and could then easily use a standard placeholder image), I'd suggest pre-loading the relevant thumbnail images before your table view's numberOfRowsInSection:
changes its return value and thus triggers the calls to tableView:cellForRowAtIndexPath:
. That way you'll be able to return fully configured images in the cells.
Upvotes: 1