Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

How to efficiently load data in UITableView?

lukeirvinlukeirvin Posts: 388Registered Users @ @
I'm loading many images into a UITableView.

Each UITableViewCell will have 5 images.

I'm using SDWebImage to load them in the background (and show a placeholder while loading or if not available).

My table scrolls smoothly and I can see the images.

The issue that I am having is that my images are showing up all over the place and in the wrong cell.

Here's my cellForRowAtIndex Path. Am I missing something or does something look off here?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * cellIdentifier = @FilterSelectCell;

    self.cell = (FilterSelectCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (self.cell == nil)
    {
        NSArray * nib = [[NSBundle mainBundle] loadNibNamed:@FilterSelectCell owner:self options:nil];
        self.cell = [nib objectAtIndex:0];

        self.cell.profilePicOne.clipsToBounds = YES;
        self.cell.profilePicOne.layer.cornerRadius = 20.0;

        self.cell.profilePicTwo.clipsToBounds = YES;
        self.cell.profilePicTwo.layer.cornerRadius = 20.0;

        self.cell.profilePicThree.clipsToBounds = YES;
        self.cell.profilePicThree.layer.cornerRadius = 20.0;

        self.cell.profilePicFour.clipsToBounds = YES;
        self.cell.profilePicFour.layer.cornerRadius = 20.0;

        self.cell.profilePicFive.clipsToBounds = YES;
        self.cell.profilePicFive.layer.cornerRadius = 20.0;
    }

    self.cell.label.text = [self.myArray objectAtIndex:indexPath.row];

    // query and display random images from parse.com
    PFQuery * query = [PFUser query];
    [query whereKey:@category equalTo:self.cell.label.text];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

        if (error)
        {
            NSLog(@Error: %@ %@", error, [error userInfo]);
        }
        else
        {
            for (int i = 0; i < objects.count; i++)
            {
                self.profilePicObject = [objects objectAtIndex:i];

                int imgRandom = arc4random() % [objects count];

                self.randomProfilePicObject = [objects objectAtIndex:imgRandom];

                self.imageFile = [self.randomProfilePicObject objectForKey:@imageFile];
                NSURL * imageFileURL = [[NSURL alloc] initWithString:self.imageFile.url];
                NSData * imageData = [NSData dataWithContentsOfURL:imageFileURL];
                UIImage * aImage = [[UIImage alloc] initWithData:imageData];

                self.cell.profilePicOne.image = aImage;
            }
    }

    return self.cell;
}

Replies

  • RickSDKRickSDK Posts: 1,236Registered Users @ @ @ @
    i think you need a unique cellIdentifier.

    I used this line:

    NSString *cellIdentifier = [NSString stringWithFormat:@cellIdentifier%dRow%d, indexPath.section, indexPath.row];
  • lukeirvinlukeirvin Posts: 388Registered Users @ @
    that was it!

    Is there a way to load images and keep them the same while on this view?

    Meaning, right now, if I scroll out of a cell area, and then go back to it, the image changes.

    I only want the images to change if I push to another view controller and go back, or if the app is killed and relaunched.
  • RickSDKRickSDK Posts: 1,236Registered Users @ @ @ @
    yes. the problem is you are generating a random image every time cellForRowAtIndexPath is called. Which means as you scroll up and down it constantly hits that method.

    you woul do better to have a global array that you populate in viewDidLoad, and randomly assign the array just once. From there you simply access the array in cellForRowAtIndexPath and by doing that your cells will keep their same images throughout the life of the view.
  • Duncan CDuncan C Posts: 9,112Tutorial Authors, Registered Users @ @ @ @ @ @ @
    RickSDK wrote: »
    i think you need a unique cellIdentifier.

    I used this line:

    NSString *cellIdentifier = [NSString stringWithFormat:@cellIdentifier%dRow%d, indexPath.section, indexPath.row];

    ACK. No, no, no! That is a very bad idea. It causes every single cell to be unique, completely defeating cell reuse, and making your app's memory footprint grow and grow.

    Instead you and the OP both should fix your cell reuse bugs.
    Regards,
    Duncan C
    WareTo

    widehead.gif
    Animated GIF created with Face Dancer, available for free in the app store.

    I'm available for one-on-one help at CodeMentor
  • Duncan CDuncan C Posts: 9,112Tutorial Authors, Registered Users @ @ @ @ @ @ @
    lukeirvin wrote: »
    that was it!

    Is there a way to load images and keep them the same while on this view?

    Meaning, right now, if I scroll out of a cell area, and then go back to it, the image changes.

    I only want the images to change if I push to another view controller and go back, or if the app is killed and relaunched.

    The problem you're having has to do with cell reuse. Everybody wrestles with this when they first start using table views.

    When a cell scrolls off-screen, it gets put in a reuse queue. Then, next time you need a cell, you call the cell dequeue method and you might get back a cell that was used before. When you get back a recycled cell, you should assume that it has all the correct fields in it (custom labels/UIImageViews/switches that you've added) but that all the contents are wrong. You have to fully configure the cell with new data.

    You should set up your async downloading to save the images that are downloaded into your data model and then update the cell.

    When you go to display a cell, if the data model does not contain one or more of the images, display placeholders and make the async call to load the image(s). If the data is still in the model from the last time you displayed the cell, then use it.

    The key thing is to remember to set value for all the fields in your cell, since they may contain leftovers from the last time the cell was used.
    Regards,
    Duncan C
    WareTo

    widehead.gif
    Animated GIF created with Face Dancer, available for free in the app store.

    I'm available for one-on-one help at CodeMentor
  • ebender001ebender001 MissouriPosts: 173Registered Users @ @
    The key thing is to remember to set value for all the fields in your cell, since they may contain leftovers from the last time the cell was used.

    Or how 'bout overriding prepareForReuse in the cell subclass and nil stuff out? I use this all the time for collection view cells and this post made me check the uitableviewcell doc - lo and behold, its there, too.
  • lukeirvinlukeirvin Posts: 388Registered Users @ @
    meaning nil out the images/labels in the Cell?
Sign In or Register to comment.