UITableViewCells中的图像加载错误 [英] Images in UITableViewCells are loading wrong

查看:83
本文介绍了UITableViewCells中的图像加载错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,我希望在带有自定义单元格的UITableView中显示几乎与屏幕大小相同的图像。
图像加载好,有点慢但加载,但当我在TableView中滚动它们出现在错误的单元格(例如Cell5中的Image1应该出现Image5)1或2秒后正确图像出现。
为了不需要很多datatraffic,我想到了像这样的缓存类似的URL /图像存储:

I'm working on an app where I wanna show images, nearly as big as screensize, in a UITableView with custom cells. The Images are loading good, a bit slow but they load, but when I scroll in the TableView they appear in the wrong Cell (for example Image1 in Cell5 where Image5 is supposed to appear) after 1 or 2 seconds the correct image appears. In Order not to have to many datatraffic I thought about a "cache"-like URL/Image storage like this:

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

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

The URL and the rest of the data I need I'm loading via AFNetwork like this:

- (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的方法:

Here is how i fill the 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

所以感谢任何有用的提示

so thanks for any helpful hints

推荐答案

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

The table view cells are being reused for performance reason, so they will retain the previously used image in the UIImageView if you do not set it to anything before you load the image.

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

Right before you call the startLoadingImageWithUrl, you can set the initial image of the imageView with a placeholder image first or maybe add loading indicator on top of the imageView. But remember to remove the loading indicator when the real image is loaded.

- (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中的参数。尝试传递indexPath并使用indexPath找到正确的单元格,更新单元格图像视图。

And for the image appearing at the wrong cell after the image is loaded, it is because you are passing item, which is reused cell, as a parameter in the startLoadingImage and didLoadImage. Try to pass indexPath instead and locate the correct cell with the indexPath, the update the cell image view.

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

这篇关于UITableViewCells中的图像加载错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆