Reusing UITableViewCell with GCD

I use Grand Central Dispatch to download images UITableViewCellasynchronously. This works well, except in some borderline cases where the cell is reused and the previous block loads the wrong image.

My current code is as follows:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    NSString *imagePath = [self imagePathForIndexPath:indexPath];         
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);

    dispatch_async(queue, ^{
        UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

        dispatch_sync(dispatch_get_main_queue(), ^{
            cell.imageView.image = image;
            [cell setNeedsLayout];
        });
    });

    return cell;
}

As far as I know, GCD queues cannot be stopped. How can this borderline case be prevented? Or should I use something else instead of a GCD to solve this problem?

+5
source share
5 answers

, , NSOperation ivar . , . . / , , . , -main. , , .

+3

reset , .

, , async

:

cell.imageView.image = nil; // or a placeHolder image
dispatch_async(queue, ^{
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

    dispatch_sync(dispatch_get_main_queue(), ^{
        cell.imageView.image = image;
        [cell setNeedsLayout];
    });
});

EDIT:

@hgpc:

, . . - hgpc 9

, , ...

, , - counter, (-) , , == 1 , :

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (!cell) {
    // MyCustomUITableViewCell has a property counter
            cell = [[[MyCustomUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
            cell.counter = 0;
        }

        NSString *imagePath = [self imagePathForIndexPath:indexPath];         
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);

        cell.imageView.image = nil; // or a placeHolder image
        cell.counter = cell.counter + 1;
        dispatch_async(queue, ^{
            UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

            dispatch_sync(dispatch_get_main_queue(), ^{
                if (cell.counter == 1){
                    cell.imageView.image = image;
                   [cell setNeedsLayout];
                }
                cell.counter = cell.counter - 1;

            });
        });

    return cell;
}
+1

.

0

.

a) NSOperationQueue GDC.
NSOperation GDC , , .
concurrency apple.

b) async-.
.
AFNetworking ( AFNetworking+UIImageView) .

(, ..), a), b).


, , .
- :

  • imageWithContentsOfFile: imageNamed:. , imageNamed: , imageWithContentsOfFile: - . imageWithContentsOfFile: NSCache .

  • TableView ( ). 100x100 kb, , , , .

0

, ? cellForRowWithIndexPath: , .

Instead of loading images whenever cells are deleted, you can do this on viewDidLoad(or whenever your data model is initialized) and on scrollViewDidEndDecelerating:.

-(void)viewDidLoad {
    [super viewDidLoad];
    [self initializeData];
    [self loadVisibleImages];
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    if (scrollView == self.tableView) {
        [self loadVisibleImages];
    }
}

-(void)loadVisibleImages {
    for (NSIndexPath *indexPath in [self.tableview indexPathsForVisibleRows]) {
        dispatch_async(queue, ^{
            NSString *imagePath = [self imagePathForIndexPath:indexPath]; 
            UIImage *image = [UIImage imageWithContentsOfFile:imagePath];        
            dispatch_sync(dispatch_get_main_queue(), ^{
                UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPath];
                cell.imageView.image = image;
                [cell setNeedsLayout];
            });
        });
    }
}
0
source

All Articles