ios - UITableView 和解析 - 滞后

标签 ios objective-c uitableview uiscrollview parse-platform

我在我的 IOS 8 Objective-c iPhone 应用程序中使用带有 Parse 的 PFQueryTableViewController。

我的列表由一个标签和一个 UIImageView 组成,其中标签文本和图像都是从我的 Parse 核心中的一行下载的。我正在使用这段代码来实现这一点:

- (PFQuery *)queryForTable
{
    PFQuery *query = [PFQuery queryWithClassName:@"Story"];

    return query;
}

#pragma mark - Table view data source

- (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 objects] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *simpleTableIdentifier = @"cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}

// Download the header image from parse
PFFile *imageFile = [object objectForKey:@"Image"];
[imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
    if (!error) {
        UIImage *cellImage = [UIImage imageWithData:imageData];

        // Set the cellImage to the cell if it's not nil
        if (cellImage == nil) {
            // nil - do nothing
            NSLog(@"nil");
        } else {
            NSLog(@"not nil");
            // Set the image
            UIImageView *cellImageView = (UIImageView *)[cell viewWithTag:40];
            cellImageView.image = cellImage;
        }
    }
}];

// Configure the cell
UILabel *nameLabel = (UILabel*) [cell viewWithTag:10];
nameLabel.text = [object objectForKey:@"Title"];
nameLabel.textColor = [UIColor whiteColor];

// Make the cell transparent
cell.backgroundColor = [UIColor clearColor];
cell.backgroundView = [UIView new];
cell.selectedBackgroundView = [UIView new];

// Resize the cell
[cell sizeToFit];

return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Hide the tabBar and show the readButton
[self hideTabBar:self.tabBarController];

// Segue over to the viewing page
[self performSegueWithIdentifier:@"detailSegue" sender:self];

// Get the tapped cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

NSString *title = ((UILabel*) [cell viewWithTag:10]).text;

// Set selectedStory
MyManager *sharedManager = [MyManager sharedManager];
sharedManager.selectedStory = title;

// Set openedStory to YES as we opened a story
openedStory = YES;
}

此代码运行良好,但滚动有点滞后,我认为这是因为每当显示单元格时它都会下载图像。我想创建一个简单的解决方案,方法是在本地创建一组图像并让它们只下载一次,但是当应用程序启动时它必须至少加载 1 次。我需要以某种方式异步运行下载方法(或其他可行的解决方案)。

我怎样才能做到这一点?

(我正在使用 Storyboard)

编辑

enter image description here

提前致谢! 埃里克

编辑 2:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell  forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (![self.shownIndexes containsObject:indexPath]) {

    [self.shownIndexes addObject:indexPath];
    UIView *weeeeCell = [cell contentView];

    weeeeCell.layer.transform = self.initialTransform;
    weeeeCell.layer.opacity = 0.8;

    [UIView animateWithDuration:1.25 delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:0.5 options:0 animations:^{
        weeeeCell.layer.transform = CATransform3DIdentity;
        weeeeCell.layer.opacity = 1;
    } completion:^(BOOL finished) {}];
}
}

                if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) {
                [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
            }

最佳答案

您对问题的假设是正确的,您对解决方案的想法也是正确的。您提到的关于预加载图像的附加要求有点模糊。

必须在表格出现之前加载它们吗?如果它们是异步加载的,它们应该是异步加载的,那么您需要阻止用户访问表,直到请求完成。您将用根本看不到表格的更糟糕体验取代无法立即看到图像的糟糕体验。

我认为更好的答案是延迟加载。解决方案的概要是:

声明一个图像字典(由 indexPaths 索引)并确保将其初始化为一个空字典...

@interface MyViewController ()  // replace 'MyViewController' with your class
@property(strong,nonatomic) NSMutableDictionary *images;
@end

在 cellForRowAtIndexPath 中使用该集合...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
    static NSString *simpleTableIdentifier = @"cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }

    UIImageView *cellImageView = (UIImageView *)[cell viewWithTag:40];
    UIImage *cachedImage = self.images[indexPath];
    if (cachedImage) {
        cellImageView.image = cachedImage;
    } else {
        cellImageView.image = // put a place holder image here

        // load lazily, but read on.  the code in the callback should assume
        // nothing about the state of the table when it runs

        PFFile *imageFile = [object objectForKey:@"Image"];
        [imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
            // what if this gets run a second time before the first request finishes?
            // no worries, check for that here:
            if (!error && !self.images[indexPath]) {
                UIImage *cellImage = [UIImage imageWithData:imageData];
                self.images[indexPath] = cellImage;
                // this is important:  don't refer to cell in here, it may be
                // scrolled away and reused by the time this closure runs
                // the code we just wrote to init the cellImageView works just fine
                // call that using reload

                if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) {
                    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
                }
            }
        }];
    }

    // Configure the cell
    UILabel *nameLabel = (UILabel*) [cell viewWithTag:10];
    nameLabel.text = [object objectForKey:@"Title"];
    nameLabel.textColor = [UIColor whiteColor];

    // Make the cell transparent
    cell.backgroundColor = [UIColor clearColor];
    cell.backgroundView = [UIView new];
    cell.selectedBackgroundView = [UIView new];

    // Resize the cell
    [cell sizeToFit];

    return cell;
}

编辑——暂时不要理会这个,但是——如果你真的有机会在显示之前准备 View (比如这个 View Controller 可能在标签栏容器中而不是默认标签中) .您可以使用 TableView 辅助方法来预取可见行...

- (void)prepareToBeShown {
    NSArray indexPaths = [self.tableView indexPathsForVisibleRows];
    [self.tableView reloadRowsAtIndexPaths:indexPaths];    
}

编辑 2:

    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell  forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (![self.shownIndexes containsObject:indexPath]) {

        [self.shownIndexes addObject:indexPath];
        UIView *weeeeCell = [cell contentView];

        weeeeCell.layer.transform = self.initialTransform;
        weeeeCell.layer.opacity = 0.8;

        [UIView animateWithDuration:1.25 delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:0.5 options:0 animations:^{
            weeeeCell.layer.transform = CATransform3DIdentity;
            weeeeCell.layer.opacity = 1;
        } completion:^(BOOL finished) {}];
    }
}

关于ios - UITableView 和解析 - 滞后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26433042/

相关文章:

ios - 重用 UITableViewCells 来显示喜欢的状态?

uitableview - 在 UITableViewCell 中显示 UIMenuController,分组样式

ios - 按钮的动画图像旋转

ios - 如何正确设置背景图像

objective-c - NSObject 内的部分方法未执行

iphone - 从 uitableviewcell 拖放到 ios 中的 uiimage View

objective-c - 将 Objective-C 枚举常量转换为字符串名称

ios - 自定义TableView和标题

iphone - 如何更改导航栏高度

ios - swift : Pass UITableViewCell label to new ViewController ** CRASHING **