0

My app needs to display huge number of images(about 2000) in a UITableView. Basically, I use the following code to construct my UITableViewCell:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    } 

    // Some Operations...

    NSString *path = [self.dataArray jk_objectWithIndex:indexPath.row];
    UIImage *img = [UIImage imageWithContentsOfFile:path];
    cell.imageView.image = img;

    return cell;
}

This works but when the tableview loads, memory increase fast and it seems that all the images is loaded to the memory.

Is there any good ideas to deal with this? I just want to save the memory.

BTW, anyone knows what the common way is to achieve this need? I think loading all the images to memory is the stupidest way... And the code I initial rows of tableview is the following:


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    if (!_isLoading) {
        return self.dataArray.count; // about 2000... That's terrible
    } else {
        return 0;
    }
}

Thanks!

Tony.Lee
  • 662
  • 1
  • 7
  • 14
  • Does your image come from Local or WebAPI? – Parth Patel Apr 22 '19 at 06:42
  • 2
    Use https://github.com/SDWebImage/SDWebImage if you want load image from server – Hitesh Surani Apr 22 '19 at 06:43
  • My images come from Local. – Tony.Lee Apr 22 '19 at 06:46
  • The problem that you have is coming from the image cache. Every image is cached and it increases the used memory. I think you can try to create different image caches and to clean the caches which are far from the current index of the table view. – m1sh0 Apr 22 '19 at 07:02
  • @m1sh0 Thanks for your suggestion. When the tableview didn't come to screen, everything is OK. The dataArray contains the paths of the images, not the image itself. – Tony.Lee Apr 22 '19 at 07:11
  • @dahiya_boy Could you explain it more detail...? – Tony.Lee Apr 22 '19 at 07:13
  • yes but every time when you display an image the image is cached in the default cache and this is the default behavior. And once when you close the view controller the cache continues keeping the images. Check this https://stackoverflow.com/a/8272227/1856499 – m1sh0 Apr 22 '19 at 07:14
  • I don't have anything more specific. But you can check here https://developer.apple.com/documentation/uikit/uiimage . And on init(named ... ) it says "Because these methods cache the image data automatically, ". I have such a memory problem when I did animation with 50 images. – m1sh0 Apr 22 '19 at 07:29
  • @m1sh0 I have already called -imageWithContentsOfFile: not -init(named ... ). Still, you bring me a new idea for this. – Tony.Lee Apr 23 '19 at 01:52

2 Answers2

1

There are two problems with your code.

  • First, and most important, the images are large but the display of the images in the table is small. That's wrong. You should load the image only at the size you actually need for display.

  • Second, images are cached by default. You need to prevent the caching of these images as they are loaded.

You can easily do both of those things in your cellForRowAt by using the ImageIO framework.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

I figure out a way to this question. Add these lines of code to cellForRowAtIndexPath:

CGRect rectInTableView = [tableView rectForRowAtIndexPath:indexPath];
    CGRect rectInSuperview = [tableView convertRect:rectInTableView toView:[tableView superview]];
    if ( rectInSuperview.origin.y > SCREEN_HEIGHT || rectInSuperview.origin.y + rectInSuperview.size.height < 0 ) {
        cell.imageView.image = self.placeholder;
    } else {
        NSString *path = [self.dataArray jk_objectWithIndex:indexPath.row];
        UIImage *img = [UIImage imageWithContentsOfFile:path];
        cell.imageView.image = img;
    }

First I check whether the cell is shown on the screen. If yes, the imageView show my data images. If not, it show the placeholder instead. Also, the placeholder is init with [UIImage imageNamed:]. This is the best way because it will be used frequently.

Tony.Lee
  • 662
  • 1
  • 7
  • 14