Why are my UITableViewCell images only being loaded when I leave then return to a controller and not during viewDidLoad?

StackOverflow https://stackoverflow.com//questions/22005817

Domanda

Having a slight problem with my UITableViewCell images. I'm loading my data straight from parse.com. My objects array that returns PFObject's is stored inside an NSMutable array named "people".

This is how I display the data in my table:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

        // Configure the cell...

        Person *current;
        if (tableView == [[self searchDisplayController] searchResultsTableView]) {
            current = [searchResults objectAtIndex:indexPath.row];
        } else {
            current = [people objectAtIndex:[indexPath row]];
        }

        [[cell textLabel] setText: [current valueForKey:@"name"]];

        PFFile *userImageFile = [current valueForKey:@"image"];
        [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
            UIImage *image = [UIImage imageWithData:imageData];
            [[cell imageView] setImage: image];
        }];

        //  [[cell imageView] setImage: [current image]];
        [[cell detailTextLabel] setText: [current valueForKey:@"notes"]];


    return cell;
}

The problem is when I load the app up and this view which is my main loads it doesn't load any images. However when I tap on a row just before the next controller is popped on screen I see the image for that row load and then when I tap the back button and go back to the main view again the rest of the tableViews images load.

Is this something to do with the images not being thumbnail versions?

I've tried wrapping the code in dispatch_async(dispatch_get_main_queue(), ^ { )}; with no luck. Can someone help me solve this issue?

Kind regards

Update to show where I call reload data:

-(void)viewDidAppear:(BOOL)animated {
    dispatch_async(dispatch_get_main_queue(), ^{
        [[self tableView] reloadData];
    });
}
- (void)viewDidLoad
{
    [super viewDidLoad];


    people = [[NSMutableArray alloc] init];

    PFQuery *query = [PFQuery queryWithClassName:@"People"];
    [query whereKey:@"active" equalTo:@1];

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        people = objects.mutableCopy;
    dispatch_async(dispatch_get_main_queue(), ^ {
            [[self tableView] reloadData];
    });
È stato utile?

Soluzione 2

Instead of loading my data directly from parse.com into my tableView I loaded it into an object first. So each object was no longer an PFObject and now a Person object and I stored these in a mutable array which I accessed in my tableView.

Altri suggerimenti

I don't think there is anything wrong with your loading in your viewDidLoad.

My suspicion is that the UIImageView's frame is actually zero as you did not have a placeholder image while loading the actual images. The cell will not be redrawn again until the next time layoutSubviews is called again, even if your fetched image has loaded. So either set a placeholder image, or call:

[cell setNeedsLayout];  

once your image is fully loaded.

Another alternative is to use PFImageView, a subclass of UIImageView, which takes care of everything for you.

PFFile *userImageFile = [current valueForKey:@"image"];
[cell imageView].image = [UIImage imageNamed:@"placeholder.jpg"]; // placeholder image
[cell imageView].file = userImageFile;
[[cell imageView] loadInBackground];

Try it:

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear]; //this is necessary for most time
    //viewDidAppear be called in main thread, so just call reloadData directly
    [self.tableView reloadData];
}

As mentioned in Apple document about - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath:

You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.

If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method.

For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.

So, do you forget to use the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling cellForRowAtIndexPath method?

Here is a discussion about this.

How I am doing this
In my UIViewController.m
@property (nonatomic, strong) NSMutableDictionary *imageDownloadsInProgress;
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.imageDownloadsInProgress = [NSMutableDictionary dictionary];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    SRKProduct *productRecord = [stockArray objectAtIndex:indexPath.row];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    if (!productRecord.image || [productRecord.image isEqualToData:NULL] || productRecord.image.length == 0) {
        if (_itemTableView.dragging == NO && _itemTableView.decelerating == NO)
        {
            [self startIconDownload:productRecord forIndexPath:indexPath];
        }
        cell.imageView.image = [[UIImage imageNamed:@"Placeholder.png"] makeThumbnailOfSize:CGSizeMake(50,50)];//This is just a placeholder and will be removed when original image is downloaded.
    }
return cell;
}
#pragma mark -
- (void)startIconDownload:(SRKProduct *)srkproduct forIndexPath:(NSIndexPath *)indexPath
{
    SRKIconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];
    if (iconDownloader == nil)
    {
        iconDownloader = [[SRKIconDownloader alloc] init];
        iconDownloader.srkproduct = srkproduct;
        [iconDownloader setCompletionHandler:^{

            UITableViewCell *cell = [_itemTableView cellForRowAtIndexPath:indexPath];

            // Display the newly loaded image
            cell.imageView.image = [UIImage imageWithData:srkproduct.image];
            NSLog(@"Image %d",[productAdapter updateproductImage:srkproduct]);

            // Remove the IconDownloader from the in progress list.
            // This will result in it being deallocated.
            [self.imageDownloadsInProgress removeObjectForKey:indexPath];

        }];
        [self.imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
        [iconDownloader startDownload];
    }
}

Then in SRKIconDownloader.h
@interface SRKIconDownloader : NSObject

@property (nonatomic, strong) SRKProduct *srkproduct;
@property (nonatomic, copy) void (^completionHandler)(void);

And in SRKIconDownloader.m
@implementation SRKIconDownloader

#pragma mark

- (void)startDownload
{
    PFQuery *queryCouple = [PFQuery queryWithClassName:@"Product"];
    [queryCouple whereKey:@"Name" equalTo:_srkproduct.productName];


    [queryCouple findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
            if ([objects count] > 0) {
                for (PFObject *object in objects) {
                     PFFile *image = (PFFile *)[object objectForKey:@"Image"];

                    [image getDataInBackgroundWithBlock:^(NSData *data, NSError *error){
                        _srkproduct.image = data;
                        // call our delegate and tell it that our icon is ready for display
                        if (self.completionHandler)
                            self.completionHandler();
                    }];

                    break;
                }
            }
            else{
            }
        }
    }];
}



@end
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top