Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

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

iphone - Objective C Custom Lazy Load Images UITableView Cell

First time loading remote images into an iPhone app, and would like some help optimizing the process. What I've currently done is get the image if it doesn't exist, and cache it. The major goals are to:

  • only load images when needed.
  • save images for future use to reduce data consumption, and allow the user to have a somewhat functional app when not connected to the internet.

I just don't think I'm doing it well enough.

Here's a snippet of the code within tableView:cellForRowAtIndexPath:

MVImageCell * cell = (MVImageCell *)[tableView dequeueReusableCellWithIdentifier:@"PicsAndVideosCell"];

// empty cell
cell.imageView.image = nil;
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;

// set cell properties
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 2;
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
cell.imageView.frame = CGRectMake(15, 6, 58, 58);
cell.imageView.layer.cornerRadius = 6;
cell.imageView.layer.masksToBounds = YES;

Photoset * sfc = [self.myarray objectAtIndex:indexPath.row];
cell.cid = sfc.sfcid;
cell.ctitle = sfc.title;
cell.cimg = sfc.cover;

cell.textLabel.text = sfc.title;
cell.detailTextLabel.text = sfc.date;

// set cell image
MVImage * thumb = [[MVImage alloc] init];
NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? @"2" : @"";
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"Settings_SFCCovers%@_%@", retina, cell.cid]]]) {
    thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"Settings_SFCCovers%@_%@", retina, cell.cid]]];

    [cell.imageView setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f]];
    [cell bringSubviewToFront:[cell.imageView superview]];
} else {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        dispatch_sync(dispatch_get_main_queue(), ^{
            thumb.data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", cell.cimg]]];
            thumb.title = cell.ctitle;
            [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:thumb] forKey:[NSString stringWithFormat:@"Settings_SFCCovers%@_%@", retina, cell.cid]];

            [cell.imageView setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f]];
            [cell bringSubviewToFront:[cell.imageView superview]];
        });
    });
}

return cell;

Should I use a SQLite database instead of NSUserDefaults?

I'm also having trouble with the asynchronous loading. I feel like it's supposed to look like this:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
    thumb.data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", cell.cimg]]];
    thumb.title = cell.ctitle;
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:thumb] forKey:[NSString stringWithFormat:@"Settings_SFCCovers%@_%@", retina, cell.cid]];

    dispatch_sync(dispatch_get_main_queue(), ^{
        [cell.imageView setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f]];
        [cell bringSubviewToFront:[cell.imageView superview]];
    });
});

But that obviously saves the wrong image data to the NSUserDefault destination.

Any help on this, pointers on my coding style, and anything else is greatly appreciated.

Thanks!

See Question&Answers more detail:os

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

1 Answer

0 votes
by (71.8m points)

Just having a quick look at your code - you seem to be pushing blocks onto asynchronous queues, but you are calling UI code in those blocks.

You should only run UI code on the main thread.

As for a solution - have a look at some of the open source implementations to either give you an idea of what you should be doing, or just use them directly.

One such is AsyncImageView on Github.

There are others that a quick search will bring up.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...