Ios 如何减少UITableView的工作量?

Ios 如何减少UITableView的工作量?,ios,objective-c,uitableview,parsing,uiimageview,Ios,Objective C,Uitableview,Parsing,Uiimageview,我正在创建一个UITableViewController来显示曲棍球队的花名册。tableViewController调用web以获取玩家的统计信息和一张小图片,并显示在tableViewCell中。然而,当我在TableView中滚动时,它并不平滑。它的锯齿状令人难以置信。我怎样才能使播放器的图片在屏幕上显示之前不加载(如果这会减少其工作负载)?以下是我当前的代码(我已将UITableViewCell子类化): 编辑:我已经编辑了我的代码以跟随下面的注释。imagesCache属性实际上是一个

我正在创建一个UITableViewController来显示曲棍球队的花名册。tableViewController调用web以获取玩家的统计信息和一张小图片,并显示在tableViewCell中。然而,当我在TableView中滚动时,它并不平滑。它的锯齿状令人难以置信。我怎样才能使播放器的图片在屏幕上显示之前不加载(如果这会减少其工作负载)?以下是我当前的代码(我已将UITableViewCell子类化):

编辑:我已经编辑了我的代码以跟随下面的注释。imagesCache属性实际上是一个UIMutableDictionary(令人困惑,抱歉)。但是,现在我得到了一个错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: object cannot be nil (key: http://app-assets3.sportngin.com/app_images/noPhoto-square.jpg?1428933774)'
*** First throw call stack:
(0x1865f6530 0x1975cc0e4 0x1864e1348 0x1000496a8 0x185f87168 0x1874d3be8 0x187425374 0x187414ecc 0x1874d694c 0x1000acf94 0x1000b7db8 0x1000b02c4 0x1000ba5d4 0x1000bc248 0x197dfd22c 0x197dfcef0)
libc++abi.dylib: terminating with uncaught exception of type NSException
这是我的密码:

#import "RosterTableTableViewController.h"
#import "TFHpple.h"
#import "RosterListing.h"
#import "RosterListingCellTableViewCell.h"

@interface RosterTableTableViewController ()

@property (nonatomic, strong) NSMutableArray *rosters;
@property (nonatomic, strong) NSMutableDictionary *imagesDictionary;
@property NSMutableDictionary *imageCache;

@end

@implementation RosterTableTableViewController

- (void) loadRoster
{
    NSURL *RosterURL = [NSURL     URLWithString:@"http://www.lancers.com/roster/show/1502650?subseason=197271"];
    NSData *RosterHTMLData = [NSData dataWithContentsOfURL:RosterURL];

    TFHpple *RosterParser = [TFHpple hppleWithHTMLData:RosterHTMLData];

    // Get the data

    NSString *RosterNumberPathQueryString =     @"//tbody[@id='rosterListingTableBodyPlayer']/tr/td[@class='number']";
    NSArray *RosterNumberNodes = [RosterParser     searchWithXPathQuery:RosterNumberPathQueryString];
    NSString *RosterNamePathQueryString =     @"//tbody[@id='rosterListingTableBodyPlayer']/tr/td[@class='name']/a";
    NSArray *RosterNameNodes = [RosterParser     searchWithXPathQuery:RosterNamePathQueryString];
    NSString *RosterImagePathQueryString =     @"//tbody[@id='rosterListingTableBodyPlayer']/tr/td[@class='photo']/a/img";
    NSArray *RosterImageNodes = [RosterParser searchWithXPathQuery:RosterImagePathQueryString];

    NSMutableArray *rosterItems = [[NSMutableArray alloc] initWithCapacity:0];

for (int i = 0; i < RosterNumberNodes.count; ++i) {
    RosterListing *thisRosterListing = [[RosterListing alloc] init];
    thisRosterListing.playerNumber = [[[RosterNumberNodes objectAtIndex:i] firstChild] content];
    thisRosterListing.playerName = [[[RosterNameNodes objectAtIndex:i] firstChild] content];
    thisRosterListing.playerURL = [[RosterNameNodes objectAtIndex:i] objectForKey:@"href"];

        @try {
            thisRosterListing.playerImageURL = [[RosterImageNodes objectAtIndex:i] objectForKey:@"src"];
        }
        @catch (NSException *e) {}
    /*
    NSLog(@"%@", thisRosterListing.playerNumber);
    NSLog(@"%@", thisRosterListing.playerName);
    NSLog(@"%@", thisRosterListing.playerURL);
    NSLog(@"%@", thisRosterListing.playerImageURL);
    */

    [rosterItems addObject:thisRosterListing];
}

self.rosters = rosterItems;

}

- (instancetype) initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
    self.navigationItem.title = @"Roster";
    self.imageCache = [[NSMutableDictionary alloc] init];
}

    return self;
}


- (void)viewDidLoad {
[super viewDidLoad];

[self loadRoster];

// Load the Cell NIB file
UINib *nib = [UINib nibWithNibName:@"RosterListingCellTableViewCell" bundle:nil];

// Register this NIB, which contains the cell
[self.tableView registerNib:nib forCellReuseIdentifier:@"RosterCell"];

// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
        return 54;
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return self.rosters.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Get a new or recycled cell
RosterListingCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RosterCell" forIndexPath:indexPath];

RosterListing *thisRosterListing = [self.rosters objectAtIndex:indexPath.row];
cell.playerNumberLabel.text = thisRosterListing.playerNumber;
cell.playerNameLabel.text = thisRosterListing.playerName;




__block UIImage *image = [self.imageCache objectForKey:thisRosterListing.playerImageURL];
cell.imageView.image = image;
if(image == nil) {
    //If nil it's not downloaded, so we download it,
    //We MUST download in a separate thread otherwise the scroll will be really slow cause the main queue will try to download each cell as they show up and every time they show up
    NSURL *imageURL = [NSURL URLWithString: thisRosterListing.playerImageURL];
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:imageURL
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                //Completion Handler is executed in an async way
                                                if([self.imageCache objectForKey:thisRosterListing.playerImageURL] == nil)
                                                    self.imageCache[thisRosterListing.playerImageURL] = image;
                                                //We need to execute the image update in the main queue otherwise it won't work
                                                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                                    RosterListingCellTableViewCell *aCell = (RosterListingCellTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
                                                    aCell.imageView.image = image;
                                                }];
                                            }];

    [dataTask resume];
}

return cell;
}
#导入“RosterTableViewController.h”
#导入“TFHpple.h”
#导入“RosterListing.h”
#导入“RosterListingCellTableViewCell.h”
@接口RosterTableTableViewController()
@属性(非原子,强)NSMutableArray*名册;
@属性(非原子,强)NSMutableDictionary*imagesDictionary;
@属性NSMutableDictionary*imageCache;
@结束
@RosterTableViewController的实现
-(作废)装货名册
{
NSURL*RosterURL=[NSURL URLWithString:@”http://www.lancers.com/roster/show/1502650?subseason=197271"];
NSData*RosterHTMLData=[NSData DATA with contentsofURL:RosterURL];
TFHpple*RosterParser=[TFHpple-hppleWithHTMLData:RosterHTMLData];
//获取数据
NSString*RosterNumber路径查询字符串=@”//tbody[@id='rosterListingTableBodyPlayer']/tr/td[@class='number']”;
NSArray*RosterNumberNodes=[RosterParser searchWithXPathQuery:RosterNumberPathQueryString];
NSString*RosterNamePathQueryString=@//tbody[@id='rosterListingTableBodyPlayer']/tr/td[@class='name']/a”;
NSArray*RosterNameNodes=[RosterParser searchWithXPathQuery:RosterNamePathQueryString];
NSString*RosterImagePathQueryString=@//tbody[@id='rosterListingTableBodyPlayer']/tr/td[@class='photo']/a/img”;
NSArray*RosterImageNodes=[RosterParser searchWithXPathQuery:RosterImagePathQueryString];
NSMutableArray*rosterItems=[[NSMutableArray alloc]initWithCapacity:0];
对于(int i=0;i@propery NSMutableDictionary *imagesDictionary;
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
//...
//We load the model information for that cell
NSDictionary *cellInfo = self.dataModel[indexPath.row];

__block UIImage *image = [self.imagesDictionary objectForKey:[cellInfo objectForKey:@"avatar"]];
cell.avatarView.image = image;
if(image == nil) {
    //If nil it's not downloaded, so we download it, 
    //We MUST download in a separate thread otherwise the scroll will be really slow cause the main queue will try to download each cell as they show up and every time they show up 
    NSURL *imageURL = [NSURL URLWithString:URL];
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:imageURL
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
       //Completion Handler is executed in an async way 
       if([self.imagesDictionary objectForKey:[cellInfo objectForKey:@"avatar"]] == nil)
                                                    if(error == nil) {
                                                      // no error
                                                      image = [UIImage imageWithData:data];
                                                    if (image == nil) {
                                                        //nil image, in my case I use a default undefined image
                                                        image = [UIImage imageNamed:@"undefined_user"];
                                                    }
                                                    //Now we are sure image is never nil
                                                    [self.imagesDictionary setObject:image forKey:[cellInfo objectForKey:@"avatar"]];
                                                    //We need to execute the image update in the main queue otherwise it won't work
                                                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                                            UITableviewCell *aCell = (UITableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
                                                            aCell.avatarView.image = image;
                                                        }];
  }];

  [dataTask resume];

  return cell;