0

I have the following bit of code:

dispatch_async(dispatch_get_global_queue(0, 0), ^
{
    [self loadThumbnails]; //loads an array of photos which get loaded into each table cell
    [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
});

in the initializer of my subclassed UITableView. I'd like it for the table to load these thumbnails on a separate thread because they take some time to load. Yet, when I execute the above code, the tableview comes up blank. So my first question is how can I fix this?

My second question is, I'd like for this dispatch queue to be killed once the tableview object is released. Is this possible / how would this be accomplished?

Tried implementing the solution from Vikings and here is what I got:

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *cellIdentifier = @"ThumbnailCell";
    UITableViewCell *tableViewCell = [self dequeueReusableCellWithIdentifier:cellIdentifier];    

    if (!tableViewCell)
    {
        tableViewCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
    }


    NSInteger thumbnailsPerCell = self.thumbnailViewsPerCell;
    NSInteger startingThumbnailIndex = indexPath.row * thumbnailsPerCell;
    NSInteger totalThumbnails = MIN(((indexPath.row * thumbnailsPerCell) + thumbnailsPerCell) , [self.thumbnailViews count]) - startingThumbnailIndex;

    if ([tableViewCell.contentView subviews])
    {
        for (UIView *subview in [tableViewCell.contentView subviews]) 
        {
            [subview removeFromSuperview];
        }
    }

    for (int i = 0; i < totalThumbnails; i++)
    {
        UIView *thumbnailView = [[UIView alloc] initWithFrame:CGRectMake(i * self.cellDimension, 0, self.cellDimension, self.cellDimension)];
        UIView *thumbnail = [[self.thumbnailCache objectForKey:[NSNumber numberWithInt:i]] retain];
        if (thumbnail)
        {
            [thumbnailView addSubview:thumbnail];
            [tableViewCell.contentView addSubview:thumbnailView];
            [thumbnailView release];
            [thumbnail release];
        }
        else 
        {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
            ^{
                UIView *thumbnail = [[self createThumbnailAtIndex:i] retain];

                if (thumbnail)
                {
                    dispatch_async(dispatch_get_main_queue(), 
                    ^{
                        UITableViewCell *tableViewCell = [self cellForRowAtIndexPath:indexPath];

                        if (tableViewCell)
                        {
                            [thumbnailView addSubview:thumbnail];
                            [tableViewCell.contentView addSubview:thumbnailView];
                            [thumbnailView release];
                            [thumbnail release];
                        }
                    });

                    [self.thumbnailCache setObject:thumbnail forKey:[NSNumber numberWithInt:i]];
                }
            });
        }
    }

    return tableViewCell;
}

This is producing a blank tableView. Any clue as to why?

Ser Pounce
  • 14,196
  • 18
  • 84
  • 169
  • Does [self loadThumbnails] block until done or does it return immediately? – rmaddy Oct 15 '12 at 23:25
  • That's the problem then. You end up calling reloadData while all the images continue to load in the background. you need to set this up such that reload data is called as each image is load or once all images have finished loading. – rmaddy Oct 15 '12 at 23:28

3 Answers3

1

It's kind of strange to mix GCD with performSelector. I would do it this way:

dispatch_async(dispatch_get_global_queue(0, 0), ^
{
    [self loadThumbnails]; //loads an array of photos which get loaded into each table cell
    dispatch_async(dispatch_get_main_queue(), ^ {
        [self reloadData];
    });
});
rmaddy
  • 314,917
  • 42
  • 532
  • 579
1

I had the same issue, and solved it perfectly, check the thread below. Just load the images in a separate thread, a technique referred to as lazy loading.

Table View Scrolling Async

Community
  • 1
  • 1
Vikings
  • 2,527
  • 32
  • 45
  • Thank you sir. I've tried implementing this exact algorithm and am getting a blank table. I've posted the code above. Any chance you could take a look? – Ser Pounce Oct 16 '12 at 23:49
  • @CoDEFRo you mention you get a blank table view with no cells? You should at least get a cell, or your method is not returning a cell. Also, why are you removing the subviews from your table view cell? – Vikings Oct 18 '12 at 01:14
  • @CoDEFRo What kind of datasource are you using for the table view? – Vikings Oct 18 '12 at 01:17
  • I'm not sure what you mean by that, I am using the UITableViewDataSource. Is that what you meant? – Ser Pounce Oct 19 '12 at 23:30
  • I was getting a blanktableview with no cells, but I fixed a bug and now it's a blanktableview with cells. I think part of the problem is the adding and removing off subviews. Maybe this type of algorithm is not needed for what I'm doing since I'm not loading from outside of my apps bundle. What do you think? – Ser Pounce Oct 19 '12 at 23:37
  • WWDC2012 Building Concurrent User Interfaces helped as well. – Ser Pounce Nov 03 '12 at 15:51
0

answering your second question: maybe you shouldn't load all thumbnails for your table. Just load those ones you need to display in separate requests. You could even cancel previous requests if cell has changed the thumbnail image. There are even libraries which do everything for you like SBWebImage

Community
  • 1
  • 1
Ezeki
  • 1,519
  • 10
  • 17
  • The OP indicates that the class is a subclass of `UITableView`. Therefore, `self` is correct. – Mac Oct 15 '12 at 23:26
  • Generally speaking, it's recommended that answers be more than just the necessary code. Explanations and the like are appreciated. You'll get more upvotes with more thorough answers. – KRyan Oct 15 '12 at 23:26
  • @Mac, you are right, sorry, i missed that thing, i will edit my answer – Ezeki Oct 15 '12 at 23:28