【问题标题】:Images in UITableViewCells are loading wrongUITableViewCells 中的图像加载错误
【发布时间】:2013-05-22 08:02:58
【问题描述】:

我正在开发一个应用程序,我想在带有自定义单元格的 UITableView 中显示几乎与屏幕尺寸一样大的图像。 图像加载良好,有点慢,但它们会加载,但是当我在 TableView 中滚动时,它们会在 1 或 2 秒后出现在错误的单元格中(例如应该出现 Image5 的 Cell5 中的 Image1)。 为了避免过多的数据流量,我考虑了一个类似“缓存”的 URL/图像存储,如下所示:

- (id) init
{
    if (self = [super init]) {
        self.cacheStoreDictionary = [NSMutableDictionary new];
    }
    return  self;
}

- (void) startLoadingImageWithUrl:(NSString *)urlString forItem:(id)item
{
    if (self.cacheStoreDictionary[urlString]) {
        UIImage *image = self.cacheStoreDictionary[urlString];
        [self.delegate lcCachedImageLoader:self didLoadImage:image forItem:item wasCacheHit:YES];
    } else {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
            UIImage *image = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.cacheStoreDictionary setObject:image forKey:urlString];
                [self.delegate lcCachedImageLoader:self didLoadImage:image forItem:item wasCacheHit:NO];
            });
        });
    }
}

我需要通过 AFNetwork 加载的 URL 和其余数据如下:

- (void)fetchTicketEvents
{
    // Login URL
    NSURL *eventsURL = [NSURL URLWithString:TH_API_BASEURL];

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:eventsURL];
    httpClient.parameterEncoding = AFJSONParameterEncoding;

    // Set request parameters
    NSDictionary *params = nil;
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET"
                                                            path:TH_API_PATH_TICKET_EVENT_INDEX
                                                      parameters:params];
    request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

    // Prepare request
    AFJSONRequestOperation *eventsRequest = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        if ([self.delegate respondsToSelector:@selector(thAPITicket:didLoadTicketEvents:response:errorCode:)]) {
            NSArray *jsonEventArray = JSON;
            NSMutableArray *event = [[NSMutableArray alloc] initWithCapacity:jsonEventArray.count];
            for (NSDictionary *eventDictionary in [JSON allObjects]) {
                [event addObject:[LCEvent eventFromDictionary:eventDictionary]];
            }
            [self.delegate thAPITicket:self
                             didLoadTicketEvents:YES
                                        response:@{@"response" : response, @"json" : JSON, @"event" : event}
                                       errorCode:TH_API_ERR_TICKETINDEX_NO_ERROR];
#if LOG_NETWORKING
            [self printJSON:JSON];
#endif
            //Network indicator off
            [LCSharedInstance hideNetworkActivity];

            //Allow Slide-To-Refresh
            [LCSharedInstance singletone].allowSlideToRefresh = YES;
            [LCSharedInstance singletone].isShownLoadingMessage = NO;
            [LCSharedInstance singletone].isLoading = NO;
        }
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        if ([self.delegate respondsToSelector:@selector(thAPITicket:didLoadTicketEvents:response:errorCode:)]) {
            if (nil == JSON) {
                JSON = @{};
            }
            [self.delegate thAPITicket:self
                             didLoadTicketEvents:NO
                                        response:@{@"response" : response, @"json" : JSON}
                                       errorCode:TH_API_ERR_TICKETINDEX_NO_ERROR];
            [LCSharedInstance hideNetworkActivity];

        }
        //Network indicator off
        [LCSharedInstance hideNetworkActivity];
    }];
    [LCSharedInstance showNetworkActivity];
    // Send request
    [eventsRequest start];
}

这是我如何填充 TableViewCell:

- (void) lcCachedImageLoader:(LCCachedImageLoader *)cachedImageLoader didLoadImage:(UIImage *)teaserImage forItem:(id)item wasCacheHit:(BOOL)wasCacheHit
{
    //Teaser Image Implementation
    UIImageView *imageView = ((UIImageView*)[((UIView*)item)viewWithTag:100]);
    imageView.alpha = 0.2;
    imageView.image = teaserImage;
    imageView.contentMode = UIViewContentModeScaleToFill;
    [UIView animateWithDuration:0.5 animations:^{
        imageView.alpha = 1.0;
    }];
}


#pragma mark - tableview delegation
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"offerCell";
    LCEvent *event = self.eventArray[indexPath.row];
    tableView = self.tableView;
    LCClusterViewController *clusterVC = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

#pragma mark - Cell Config and Style Attributes
    clusterVC.titleLabel.attributedText = LCAttrText(event.titleString, LCFontStyleEventName);
    clusterVC.ticketDetailsLabel.attributedText = LCAttrText(event.subtitleString, LCFontStyleEventTitle);
    clusterVC.oldPriceLabel.attributedText = LCAttrText(event.oldPriceString, LCFontStyleEventOldPrice);
    clusterVC.actualPriceLabel.attributedText = LCAttrText(event.actualPriceString, LCFontStyleEventPrice);
    clusterVC.timeLabel.attributedText = LCAttrText(event.timeString, LCFontStyleEventInfoText);
    clusterVC.ticketCountLabel.attributedText = LCAttrText(event.stockString, LCFontStyleEventInfoText);
    clusterVC.dateLabel.attributedText = LCAttrText(event.dateString, LCFontStyleEventDateText);
... and on and on

感谢任何有用的提示

【问题讨论】:

    标签: ios uitableview uiimage


    【解决方案1】:

    由于性能原因,表格视图单元格被重复使用,因此如果您在加载图像之前未将其设置为任何内容,它们将在 UIImageView 中保留以前使用的图像。

    在调用 startLoadingImageWithUrl 之前,您可以先使用占位符图像设置 imageView 的初始图像,或者在 imageView 顶部添加加载指示器。但是请记住在加载真实图像时删除加载指示器。

    - (void) startLoadingImageWithUrl:(NSString *)urlString forItem:(id)item
    {
        UIImageView *imageView = ((UIImageView*)[((UIView*)item)viewWithTag:100]);
        imageView.image = placeholderImage; 
        if (self.cacheStoreDictionary[urlString]) {
            UIImage *image = self.cacheStoreDictionary[urlString];
            [self.delegate lcCachedImageLoader:self didLoadImage:image forItem:item wasCacheHit:YES];
        } else {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
                NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
                UIImage *image = [UIImage imageWithData:data];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.cacheStoreDictionary setObject:image forKey:urlString];
                    [self.delegate lcCachedImageLoader:self didLoadImage:image forItem:item wasCacheHit:NO];
                });
            });
        }
    }
    

    而对于图片加载后出现在错误单元格的图片,是因为你在startLoadingImage和didLoadImage中传递了item,也就是reuseed cell,作为参数。尝试传递 indexPath 并使用 indexPath 找到正确的单元格,更新单元格图像视图。

    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

    【讨论】:

    • 是的,我也尝试过,但它使整个图像加载速度变慢,并没有真正解决问题。有些图像在短时间内仍处于错误位置。
    • 你在哪里调用 startLoadingImageWithUrl:(NSString *)urlString forItem:(id)item?
    • 在我的 cellForRowAtIndexpath 的末尾:
    • 尝试在 cellForRowAtIndexPath 中设置占位符图像?
    • 是的,我也试过了;)效果提高了 50%,但仍然有一点错误的图像错误的单元格问题。
    【解决方案2】:

    如果图像未加载,您只需在分配图像的位置编写此代码

    cell.imageView.image = Nil;
    

    如果它已加载,那么您将图像分配给 if else like this

    cell.imageView.image = Nil;
    if([dictionary objectForKey:@"Image"])
    {
        cell.imageView.image = [dictionary objectForKey:@"Image"];
    
    }else
    {
        cell.imageView.image = Nil;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-11
      • 2018-02-01
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 1970-01-01
      相关资源
      最近更新 更多