Realinstomp
Realinstomp

Reputation: 532

Image not loading immediately in Table View

I'm using SDWebImage and grabbing Images associated with a news article from a news API.

The problem is, the images for the cells on screen aren't loading until I start scrolling on the UITableView. Once I scroll past a cell, and it goes off screen, once I come back to it the Image will finally be loaded.

Here is my (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath code:

if ([feedLocal.images count] == 0) {
    [cell.imageView setImage:[UIImage imageNamed:@"e.png"]];
}
else {    
    Images *imageLocal = [feedLocal.images objectAtIndex:0];
    NSString *imageURL = [NSString stringWithFormat:@"%@", imageLocal.url];
    NSLog(@"img url: %@", imageURL);

    // Here we use the new provided setImageWithURL: method to load the web image
    __weak UITableViewCell *wcell = cell;
    [cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", imageURL]]
                   placeholderImage:[UIImage imageNamed:@"115_64.png"]
                          completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
                              if(image == nil) {
                                  [wcell.imageView setImage:[UIImage imageNamed:@"115_64.png"]];
                                   //];
                              }
                          }
    ];
}

Any idea why this would be happening? It just seems like when the UITableView loads, the Images aren't being told to load or something until scrolling begins?

Any suggestion is much appreciated, thanks!

Upvotes: 8

Views: 9034

Answers (4)

Guillaume Algis
Guillaume Algis

Reputation: 11016

There is little chance this will solve your problem, but this is too long to fit in a comment:

Tip 1:

If you are reusing cells, you should not do [wcell.imageView setImage:] in the callback. At the time the callback code is executed, there a non-null chance that wcell will point to a different cell in the table view than the one you wanted to change the image.

Instead, use the indexPath to refer to the cell you wanted to modify:

completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
    if(image == nil) {
        UITableViewCell *actualCell = [tableView cellForRowAtIndexPath:indexPath];
        [actualCell.imageView setImage:[UIImage imageNamed:@"115_64.png"]];
    }
}

Note that if the cell you wanted to change the image is not shown anymore, cellForRowAtIndexPath: will return nil, which is absolutely fine:

Return Value

An object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.

Tip 2:

There is no need to re-create a string when you already have one ;)

[NSURL URLWithString:[NSString stringWithFormat:@"%@", imageURL]]

[NSURL URLWithString:imageURL] // imageURL is already a string

Your problem:

I'm a little bit puzzled, the code you showed really is a simple application of SDWebImage "how-to" examples, and I just tested with the v3.3 of the framework, and my cells update just fine. So try to reduce your code to the bare minimum to identify the real issue.

I'd say get rid of all your application logic (the feedLocal.images for example), and just find out if the problem actually comes from SDWebImage or not.

Upvotes: 5

yazh
yazh

Reputation: 701

NSString *mainimg=[NSString stringWithFormat:@"%@",[[xmlDataDictionary valueForKeyPath:@"eg.main.img1"]objectAtIndex:indexPath.row]];
NSURL *url = [NSURL URLWithString:mainimg];
NSData *imge = [[NSData alloc] initWithContentsOfURL:url];
cell.img.image=[UIImage imageWithData:imge];

Upvotes: 0

Ben
Ben

Reputation: 28

Not sure if you have solved your problem, but I get my problem solved by the following code.

Basic idea is to set the cell reference usable inside block and manually set the cell's image in the completed method. Hope it helps.

__block UITableViewCell *cell2 = cell;

id data = [[self itemArray] objectAtIndex:[indexPath item]];

if ([data isKindOfClass:[MyItems class]]) {

    MyItems *myData = (MyItems *)data;
    [[cell2 imageView] setImageWithURL:[myData url]
                      placeholderImage:[UIImage imageNamed:@"placeHolder.png"]
                             completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
                                 // do check that this is the right cell to put your image
                                 // your methods here

                                 if (image) {
                                     [[cell2 imageView] setImage:image];
                                 }
    }];
}

For the checking if that is the right cell, I guess it is something like this (I don't have time to check it)

__block UITableViewCell *cell2 = cell;

id data = [[self itemArray] objectAtIndex:[indexPath item]];

if ([data isKindOfClass:[MyItems class]]) {

    __block MyItems *myData = (MyItems *)data;
    [[cell2 imageView] setImageWithURL:[myData url]
                      placeholderImage:[UIImage imageNamed:@"placeHolder.png"]
                             completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
                                 // do check that this is the right cell to put your image
                                 // your methods here
                                 id currentData = [[self itemArray] objectAtIndex:[indexPath item]];
                                 if ([currentData isKindOfClass:[MyItems class]] && [ [[(MyItems *)currentData url] absoluteString] isEqualToString:[[myData url] absoluteString] ]) {
                                 // it is the right cell to put in :)
                                     if (image) {
                                         [[cell2 imageView] setImage:image];
                                     }
                                 }
    }];
}

Upvotes: 1

AJ112
AJ112

Reputation: 5301

I have earlier encountered a similar issue and it turned out the images in the tableview were downloading correctly. The real issue you are facing is the refresh issue. When each image is downloaded, it has to be refreshed in order to be shown in the tableview. In my case, the downloading part was done in a separate file, so i used NSNotificationCenter to tell the tableview controller class to refresh it. Here is what you can do with your code:

if ([feedLocal.images count] == 0) {
    [cell.imageView setImage:[UIImage imageNamed:@"e.png"]];
}
else {    
    Images *imageLocal = [feedLocal.images objectAtIndex:0];
    NSString *imageURL = [NSString stringWithFormat:@"%@", imageLocal.url];
    NSLog(@"img url: %@", imageURL);

    // Here we use the new provided setImageWithURL: method to load the web image
    __weak UITableViewCell *wcell = cell;
    [cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", imageURL]]
                   placeholderImage:[UIImage imageNamed:@"115_64.png"]
                          completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
                              if(image == nil) {
                                  [wcell.imageView setImage:[UIImage imageNamed:@"115_64.png"]];
                                  [[NSNotificationCenter defaultCenter] postNotificationName:@"ImageDownloaded" object:nil];
                                   //];
                              }
                          }
    ];
}

and then you can call reload data using it as below:

- (void) imageDownloaded:(NSNotification *)notification{

    [self.tableView reloadData];
}

This way you don't need to scroll in order to see the image, instead they will be shown right after they are downloaded.

Hope this helps!

Upvotes: 0

Related Questions