Изображения в UITableViewCells загружаются неправильно

Я работаю над приложением, в котором я хочу показывать изображения размером почти с экран в UITableView с пользовательскими ячейками. Изображения загружаются хорошо, немного медленно, но они загружаются, но когда я прокручиваю в TableView, они появляются в неправильной ячейке (например, Image1 в ячейке 5, где предполагается появление Image5) через 1 или 2 секунды, появляется правильное изображение. Для того, чтобы не иметь много данных, я подумал о "кэш»-подобный 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];
            });
        });
    }
}

URL и остальные данные мне нужныm загрузка через AFNetwork примерно так:

- (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

так что спасибо за любые полезные советы

Ответы на вопрос(2)

Решение Вопроса

роизводительности, поэтому они сохранят ранее использованное изображение в 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. Попробуйте вместо этого передать indexPath и найти правильную ячейку с помощью indexPath, обновите представление изображения ячейки.

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

 d3p0nit22 мая 2013 г., 13:03
хорошо, ты прав ^^
 Valent Richie22 мая 2013 г., 10:49
Попробуйте установить заполнитель изображения ранее в cellForRowAtIndexPath?
 Valent Richie22 мая 2013 г., 11:07
Я думаю, что вы не должны передавать элемент, который является ячейкой в startLoadingImageWithUrl. Вам нужно передать indexPath и в startLoadingImageWithUrl или didLoadImage попытаться найти правильную ячейку с указанным indexPath.
 d3p0nit22 мая 2013 г., 11:01
Да, я тоже это пробовал;) Он работает на 50% лучше, но все еще с небольшим неправильным изображением проблема неправильной ячейки.
 d3p0nit22 мая 2013 г., 10:39
в конце моего cellForRowAtIndexpath:
 Valent Richie22 мая 2013 г., 10:35
Где вы вызываете startLoadingImageWithUrl: (NSString *) urlString forItem: (id) элемент?
 d3p0nit22 мая 2013 г., 10:29
Да, я тоже пытался, но это делало загрузку всего медленнее и неэто действительно решит проблему. Некоторые из изображений все еще находятся на неправильных позициях в течение короткого периода времени.

где вы назначаете изображение, если оно не загружено, то

cell.imageView.image = Nil;

если он загружен, то вы назначаете изображение, если еще как

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

}else
{
    cell.imageView.image = Nil;
}

Ваш ответ на вопрос