I am using core data in my app along with NSFetchedResultsController to populate a table. My database has 40k+ entries so the table is rather long. Each table cell has a thumbnail image that is loaded from the web using SDWebImage. All works great if I scroll slowly, if I begin to scroll fast within a couple of seconds I get a crash.
NSZombies isn't showing anything useful.
I'm guessing that it has to do with SDWebImage and loading from the web. The way SDWebImage works is by loading the image in the background then setting the downloaded image after it completes downloading (wordy). My thought is that the cells are being deallocated by the UITableView, then SDWebImage tries to set the image on the deallocated cell. So if I can determine when the UITableViewCell is going to be deallocated I can stop the SDWebImage downloading process and hopefully fix the issue.
I've tried to add
- (void)dealloc {
NSLog(@"dealloc");
}
to catch when the cell is going to be deallocated but I never get anything.
EDIT
I have my -(void)dealloc method in a subclass UITableViewCell.
EDIT Here is where/how I create the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* inventoryCellID = @"InventoryCustomCellID";
InventoryCustomCell* cell = (InventoryCustomCell *)[tableView dequeueReusableCellWithIdentifier:inventoryCellID forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(InventoryCustomCell *)cell atIndexPath:(NSIndexPath *)indexPath {
[cell formatCellWithProduct:[fetchedResultsController objectAtIndexPath:indexPath] enableAdding:NO];
cell.openThumbnailButton.tag = indexPath.row;
[cell.openThumbnailButton addTarget:self action:@selector(presentThumbnailViewWithCell:) forControlEvents:UIControlEventTouchUpInside];
}
In my custom cell this is the configuration method being called:
- (void)formatCellWithProduct:(Product*)product enableAdding:(bool)addingEnabled {
self.titleLabel.text = product.part_number;
self.partNumberLabel.text = [[[product.manufacturer allObjects] objectAtIndex:0] name];
//The SDWebImage UIImageView category method
[self.thumbImageView setImageWithURL:[NSURL URLWithString:product.photo] placeholderImage:[UIImage imageNamed:@"icon.png"]];
}
EDIT Here is the SDWebImage method that downloads the image and sets it.
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock;
{
[self cancelCurrentImageLoad];
self.image = placeholder;
if (url)
{
__weak UIImageView *wself = self;
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
__strong UIImageView *sself = wself;
if (!sself) return;
if (image)
{
sself.image = image;
[sself setNeedsLayout];
}
if (completedBlock && finished)
{
completedBlock(image, error, cacheType);
}
}];
objc_setAssociatedObject(self, &operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
Table views don't tend to allocate and deallocate table view cells much. Creating cells is expensive, so they get reused when possible, rather than being discarded when they go off screen.
The UITableViewDelegate method -tableView:didEndDisplayingCell:forRowAtIndexPath: is the better place to update cells to cancel downloads or other no-longer-relevant operations.
It does look like each call to -setImageWithURL:etc:etc: is trying to cancel previous downloads for that image view, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With