Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
438 views
in Technique[技术] by (71.8m points)

ios - UITableViewCell load images and reused cells

i need to load from web/files some UIImages. I was searching and i found in other question this code:

    if (![[NSFileManager defaultManager] fileExistsAtPath:user.image]) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,  0ul);
        dispatch_async(queue, ^{
            NSData *imageData =[NSData dataWithContentsOfURL:[NSURL URLWithString:user.imageURL]];

            [imageData writeToFile:user.image atomically:YES];
            dispatch_sync(dispatch_get_main_queue(), ^{
                UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                UIImage *image = [UIImage imageWithData:imageData];
                [self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]];
                cell.imageView.image = image;
                [cell setNeedsLayout];
                NSLog(@"Download %@",user.image);
            });
        });
        cell.imageView.image=[UIImage imageNamed:@"xger86x.jpg"];
    } else {
        NSLog(@"cache");
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,  0ul);
        dispatch_async(queue, ^{
            UIImage *image = [UIImage imageWithContentsOfFile:user.image];
            //[self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]];
            dispatch_sync(dispatch_get_main_queue(), ^{
                UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
                newCell.imageView.image=image;
                [newCell setNeedsLayout];
            });
        });
    }

But the problem is that when i scroll fast to bottom or top the images are loaded wrong and there is a short lag when it ends.

So the question is.. how can i load the UIImages in the correct cell when i use queues to fetch them? Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I suspect the incorrect images you see are a result of you not setting your place holder image in the event of you having a local copy of an image but still retrieving the local copy asynchronously. Also In the code you appended for loading the local copy you use UIImage a UIKit component on a background thread.

Also interestingly you seem to be doing some kind of UIImage caching. Adding the images to what I assume is an NSMutableArray property named imageFriends. But you seem to have commented out the cache add in the event you have a local copy of the file. Also your posted code never uses the cached UIImages.

While 2 levels of caching seems a bit overboard if you wanted to do this you could do something like this:

UIImage *userImage = [self.imageFriends objectForKey:[NSNumber numberWithInt:user.userId]];
if (userImage) { // if the dictionary of images has it just display it
    cell.imageView.image = userImage;
}
else {
    cell.imageView.image = [UIImage imageNamed:@"xger86x.jpg"]; // set placeholder image
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:user.image];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *imageData = nil;
        if (fileExists){
            imageData = [NSData dataWithContentsOfFile:user.image];
        }
        else {
            imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:user.imageURL]];
            [imageData writeToFile:user.image atomically:YES];
        }
        if (imageData){
           dispatch_async(dispatch_get_main_queue(), ^{ 
                    // UIKit, which includes UIImage warns about not being thread safe
                    // So we switch to main thread to instantiate image
               UIImage *image = [UIImage imageWithData:imageData];
               [self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]];
               UITableViewCell *lookedUpCell = [tableView cellForRowAtIndexPath:indexPath];
               if (lookedUpCell){
                   lookedUpCell.imageView.image = image;
                   [lookedUpCell setNeedsLayout];
               }
           }); 
        }
    });
}

UIImages are part of UIKit and not thread safe. But you can load the NSData on another thread.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...