【问题标题】:Downloading and caching images in a table view, wrong images being displayed在表格视图中下载和缓存图像,显示错误的图像
【发布时间】:2015-03-07 10:10:09
【问题描述】:

我有一个UITableView,每行包含四个UIButtons来代表用户。我使用 Parse.com 作为我的数据库。我的- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    FriendViewCell *cell = (FriendViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];


    for(int i =0; i<4; i++) {


        if((int)indexPath.row*4+i<[self.currentUser.friends count]) {


            FriendButton *button = cell.buttons[i];
            UILabel *label = cell.labels[i];


            [button setTag:(int)indexPath.row*4+i];
            PFObject *user =self.currentUser.friends[(int)indexPath.row*4+i];
            label.text=user[@"username"];

            UIImage *cachedImage = self.images[user[@"username"]];
            if (cachedImage) {
                //use cached image
                [button setBackgroundImage:cachedImage forState:UIControlStateNormal];
            }

            else {

                //download image
                PFFile *userImageFile = user[@"profilePic"];
                [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
                    if (!error) {
                        UIImage *image = [UIImage imageWithData:imageData];
                        [self.images setObject:image forKey:user[@"username"]];
                        //this is the line that may be confusing it
                        [button setBackgroundImage:image forState:UIControlStateNormal];
                        //check we have the right number

                        NSLog(@"Number of friends %lu, number of cached images: %lu",(unsigned long)[self.currentUser.friends count], (unsigned long)[self.images count]);

                    }
                }];

            }



        }
}

return cell;

}

我正在使用 NSMutableDictionary 来存储图像。如果图像没有出现在字典中,则将使用占位符图像。我在我的自定义 FriendViewCell 代码中我也有这个方法:

-(void)prepareForReuse {

    //this is called each time we reuse a cell
    UIImage *placeHolder = [UIImage imageNamed:@"placeHolder"];

    //reset placeholder incase we download images
    //Double check this that no images are being double used while loading..
    [self.button1 setBackgroundImage:placeHolder forState:UIControlStateNormal];
    [self.button2 setBackgroundImage:placeHolder forState:UIControlStateNormal];
    [self.button3 setBackgroundImage:placeHolder forState:UIControlStateNormal];
    [self.button4 setBackgroundImage:placeHolder forState:UIControlStateNormal];

}

在检查图像是否在字典中之前最初设置回占位符。一切正常,但我刚刚注意到,如果我对应用程序进行全新安装并且没有缓存文件,然后尝试用 100 个朋友加载表格,即每个按钮图像会不断变化,直到全部下载.我不太确定为什么会这样。我觉得这可能是因为[button setBackgroundImage:image forState:UIControlStateNormal]; 在下载图像块中,所以当我滚动时它会混淆。谁能给我一些建议吗?

【问题讨论】:

    标签: ios objective-c xcode uitableview


    【解决方案1】:

    所以我解决了这个问题。这可能对其他人有用。我的新下载块是:

    //download image
                    PFFile *userImageFile = user[@"profilePic"];
                    [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
                        if (!error) {
                            //put the image in the dictionary
                            UIImage *image = [UIImage imageWithData:imageData];
                            [self.images setObject:image forKey:user[@"username"]];
                            NSLog(@"Number of friends %lu, number of cached images: %lu",(unsigned long)[self.currentUser.friends count], (unsigned long)[self.images count]);
                            //fetch the cell again because reuse may have confused it
                            FriendViewCell *originalCell = (FriendViewCell *)[tableView cellForRowAtIndexPath:indexPath];
                            if (originalCell) {
                                FriendButton *button2 = originalCell.buttons[i];
                                [button2 setBackgroundImage:image forState:UIControlStateNormal];
                            }
    
    
    
    
                        }
                    }];
    

    我认为如果下载后我的理解是正确的,您必须返回并再次从原始 indexPath 获取单元格,如果您不这样做,由于单元格重用,它可能会将图像发送到错误的单元格。因此,创建一个新单元格FriendViewCell *originalCell = (FriendViewCell *)[tableView cellForRowAtIndexPath:indexPath], 和一个新的 UIImageView(在我的例子中为 UIButton),然后设置该图像。现在似乎工作正常,修复也很简单。

    【讨论】:

    • 你说得对,单元格可能被重复使用。一个更优雅的处理方式是[tableView reloadItemsAtIndexPaths:@[indexPath]];。然后你就完成了。您可以删除所有更新单元格的逻辑,因为您现有的数据源方法 (cellForRowAtIndexPath) 会处理这些,包括处理我们在 self.images 中缓存图像的情况。在我的回答中完成讨论stackoverflow.com/questions/15799432/…
    • @danh 谢谢!非常有用。
    猜你喜欢
    • 1970-01-01
    • 2017-02-06
    • 2011-06-29
    • 2014-03-16
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    相关资源
    最近更新 更多