Weird behaviour when loading images in NSTableView

170 views Asked by At

I'm loading images with GCD, I got some strange behaviour.

When you scroll though the table view, every album starts fetching the artwork. The NSTableCellView quickly displays many wrong artworks, until after maybe a second it finally displays the correct one and then stops.

Obviously this means, after the dispatching the variable of the NSTableCellView doesn't point to the same instance anymore, which causes to change the image of the same cell over and over again.

I tried to fix this by calling viewAtColumn:row:indexOfObject: in the dispatching block, but it does not fix the problem.

Any suggestions?


Code

- (ITAlbumTableCellView *)makeTableCellViewWithAlbum:(ITLibAlbum *)album {
    ITAlbumTableCellView *cellView = (ITAlbumTableCellView *)[self makeTableCellViewWithIdentifier:kTCVIAlbum];

    // ... Mapping Stuff

    // Set artwork
    if (![self._imageCache objectForKey:album]) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSImage *artwork = album.artwork;
            if (!artwork || !artwork.isValid) artwork = [NSImage imageNamed:@"noArtwork"];

            [self._imageCache setObject:artwork forKey:album];

            dispatch_async(dispatch_get_main_queue(), ^{
                NSTableCellView *tcv = [self.tableView viewAtColumn:0 row:[self.tableContent indexOfObject:album] makeIfNecessary:NO];
                tcv.imageView.image = artwork;
            });
        });
    } else {
        cellView.imageView.image = [self._imageCache objectForKey:album];
    }

    return cellView;
}
1

There are 1 answers

5
Gralex On BEST ANSWER

You use reusable cells, so when cell hide outside the bounds, it's reuse for display another data. Quick fix:

 - (ITAlbumTableCellView *)makeTableCellViewWithAlbum:(ITLibAlbum *)album {
ITAlbumTableCellView *cellView = (ITAlbumTableCellView *)[self makeTableCellViewWithIdentifier:kTCVIAlbum];
static int tag = 0;
tag++;
int tagForBlock = tag;
cellView.tag = tag;
if (![self._imageCache objectForKey:album]) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSImage *artwork = album.artwork;
        if (!artwork || !artwork.isValid) artwork = [NSImage imageNamed:@"noArtwork"];

        [self._imageCache setObject:artwork forKey:album];

        dispatch_async(dispatch_get_main_queue(), ^{
            if(tagForBlock != cellView.tag)
                return;
            NSTableCellView *tcv = [self.tableView viewAtColumn:0 row:[self.tableContent indexOfObject:album] makeIfNecessary:NO];
            tcv.imageView.image = artwork;
        });
    });
} else {
    cellView.imageView.image = [self._imageCache objectForKey:album];
}

return cellView;
}