Mapy Sebastian
Mapy Sebastian

Reputation: 5

Images in UITableView changes as I scroll

I'm trying to create a feed just like the one in facebook. The problem is, the image on the succeeding rows will load the images from the initial rows and then correctly load their corresponding load. When you go to the top rows, the images previously loaded are gone. I've tried lazy loading but the problem persists. You could view the video to understand the problem better. (https://www.youtube.com/watch?v=NbgYM-1xYN4)

The images are asynchronously loaded and are fetched from our server.

Here are some Code:

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

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

    return [latestPosts count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     NSDictionary * dataDict = [latestPosts objectAtIndex:indexPath.row];

    CardCell *cell = [self.feedTable dequeueReusableCellWithIdentifier:@"CardCell"];
    if (cell == nil) {
        cell = [[CardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CardCell"];
    }
    [cell layoutSubviews];

    NSURL *imageURL = [[NSURL alloc] initWithString:[dataDict objectForKey:@"post_holder_image"]];
    NSURL *postImageURL = [[NSURL alloc] initWithString:[dataDict objectForKey:@"post_image"]];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
        NSData *postImageData = [NSData dataWithContentsOfURL:postImageURL];
        dispatch_async(dispatch_get_main_queue(), ^{
            cell.brandImage.image = [UIImage imageWithData:imageData];
            cell.postImage.image = [UIImage imageWithData:postImageData];
        });
    });

    cell.brandName.text = [dataDict objectForKey:@"post_holder"];
    cell.postDateTime.text = [dataDict objectForKey:@"post_datetime"];
    cell.postMessage.text = [dataDict objectForKey:@"post_content"];

    return cell;
}

Upvotes: 0

Views: 1725

Answers (3)

Kex
Kex

Reputation: 8579

There are a few problems with the above.

As mentioned above you need to use a image as a placeholder (i.e blank white or an image of your choice) in the cell init code AND cell reuse.

You really need to cache your images, only download an image once and then store it in a dictionary. i.e.:

            UIImage *cachedImage = self.images[user[@"username"]];
            if (cachedImage) {
                //use cached image
                [button setBackgroundImage:cachedImage forState:UIControlStateNormal];
            }

            else {

                //download image and then add it to the dictionary }

where self.images is an NSMutableDictionary. You could also look into NSCache. If you don't cache the images you will find the table is very laggy when scrolling for a large number of rows because of the image conversion from data.

However this will not completely fix the problem if you start loading a table and scroll up and down very fast the images will appear to be in the wrong places and move around until they are all loaded. Cell reuse will confuse where to put the image. Make sure you put [tableView reloadItemsAtIndexPaths:@[indexPath]]; in your download block i.e.:

NSURL *imageURL = [[NSURL alloc] initWithString:[dataDict objectForKey:@"post_holder_image"]];
    NSURL *postImageURL = [[NSURL alloc] initWithString:[dataDict objectForKey:@"post_image"]];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
        NSData *postImageData = [NSData dataWithContentsOfURL:postImageURL];
        dispatch_async(dispatch_get_main_queue(), ^{
            cell.brandImage.image = [UIImage imageWithData:imageData];
            cell.postImage.image = [UIImage imageWithData:postImageData];
            [tableView reloadItemsAtIndexPaths:@[indexPath]];
        });
    });

Upvotes: 1

kocakmstf
kocakmstf

Reputation: 135

You need to set imageview.image nil or you should set your placeholder image while reusing cells. Here is same question Async image loading from url inside a UITableView cell - image changes to wrong image while scrolling Other than that if you are not using parse.com api ect. you can check https://github.com/rs/SDWebImage or https://github.com/AFNetworking/AFNetworking There are tons of answer about this topic.

[cell layoutSubviews];
cell.brandImage.image = nil;
cell.postImage.image = nil;

Upvotes: 0

prema janoti
prema janoti

Reputation: 159

Use below method of UITableViewCell in your custom cell and set the image property to nil.

hope it will work for you.

-(void)prepareForReuse{
    [super prepareForReuse];

    // Then Reset here back to default values that you want.
}

Upvotes: 2

Related Questions