I have a system that downloads a large number of large images from the Internet and displays them in custom table cells. On older devices, memory warnings are pretty fast, so I implemented a system to delete some from the table to try to deal with it, but it did not work well enough (a large number of images were deleted, which affected the user interface).
So, I thought that I could upload all the images to the deviceβs cache and then upload them from there - I implemented SDWebImage , This is great, but I still have not solved the memory allocation problem, since the images are displayed all the time and therefore are stored in memory causing failures.
It seems to me that I need to implement a system that shows images (from the cache), if the cell is displayed and hide it, if the cell is not displayed - I just got stuck on how to build such a system.
Or will it not work? Can you keep application memory low (and stop it with memory alerts / crashes) by deleting images from your table cells? Or do I just need to continue my previous decision and just delete images / cells until the memory warnings stop?
Updated with code
TableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 0) { currentIndexPath = indexPath; ImageTableCell *cell = (ImageTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; ImageDownloader *download = [totalDownloads objectAtIndex:[indexPath row]]; if (cell == nil) { cell = [[[ImageTableCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: CellIdentifier] autorelease]; } cell.imageView.image = download.image; return cell; } return nil; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int t = [totalDownloads count]; return t; }
ImageTableCell.m - Custom Cell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { self.frame = CGRectMake(0.0f, 0.0f, 320.0f, 0.0f); self.contentView.frame = CGRectMake(0.0f, 0.0f, 320.0f, 0.0f); self.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth); self.contentMode = UIViewContentModeScaleToFill; self.autoresizesSubviews = YES; self.contentView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth); self.contentView.contentMode = UIViewContentModeScaleToFill; self.contentView.autoresizesSubviews = YES; [self.imageView drawRect:CGRectMake(0.0f, 0.0f, 320.0f, 0.0f)]; self.imageView.contentMode = UIViewContentModeScaleAspectFill; self.imageView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth); self.imageView.opaque = YES; } return self; }
ImageDownloader (implements SDWebImageManagerDelegate)
-(void) downloadImage // Comes from Model class { if (image == nil) { NSURL *url = [NSURL URLWithString:self.urlString]; SDWebImageManager *manager = [SDWebImageManager sharedManager]; // Remove in progress downloader from queue [manager cancelForDelegate:self]; if (url) { [manager downloadWithURL:url delegate:self retryFailed:YES]; } } } - (void)cancelCurrentImageLoad { [[SDWebImageManager sharedManager] cancelForDelegate:self]; } - (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)_image { self.image = _image; if ([self.delegate respondsToSelector:@selector(addImageToModel:)]) [self.delegate addImageToModel:self]; } - (void)webImageManager:(SDWebImageManager *)imageManager didFailWithError:(NSError *)error; { if ([self.delegate respondsToSelector:@selector(badImage)]) [self.delegate badImage]; }