0

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];
    });
LondonGuy
  • 10,778
  • 11
  • 79
  • 151

4 Answers4

0

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.

Community
  • 1
  • 1
simalone
  • 2,768
  • 1
  • 15
  • 20
  • I'm getting no visible interface for UITableViewController declares the selector viewDidAppear. – LondonGuy Feb 25 '14 at 06:40
  • @LondonGuy UITableViewController is SubClass of UIViewController where declares `viewDidAppear `. Therefore, add `[super viewDidAppear];` should be better. Even though, the comment of `viewDidAppear ` in UIViewController is `Default does nothing`, but the description of 'viewDidAppear' is `You can override this method to perform additional tasks associated with presenting the view. If you override this method, you must call super at some point in your implementation.` – simalone Feb 25 '14 at 06:51
  • @LondonGuy,because I haven't seen the register method in your code, so is it the problem? Just a guess, hope to help. – simalone Feb 26 '14 at 03:02
0

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];
Ken Toh
  • 3,721
  • 1
  • 24
  • 30
  • The way I solved this was to load data from parse.com into a Person object before loading it into my UITable. – LondonGuy Feb 25 '14 at 17:25
0

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.

LondonGuy
  • 10,778
  • 11
  • 79
  • 151
0
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
Saurav
  • 179
  • 2