防止UITableViewCell的UIImageView调整异步加载的UIImage的大小

时间:2013-08-01 09:10:17

标签: iphone ios objective-c asynchronous uiimageview

我在UIImageView中异步加载UITableViewCell。我的图像视图是100点乘100点的正方形,但我检索的UIImage并不总是具有相等的宽度和高度。

我的问题是:在加载单元格时,UIImageView s都是100乘100,这很好,但内部UIImage被拉伸到那个大小(左图)。当我按下单元格并突出显示时,图像突然调整到正确的比例(右图)。此外,当我进一步向下滚动到UITableView时,所有图像也都是100x100并且被拉伸,但是当我向上滚动以再次看到细胞时,它们会突然调整大小。但我不知道他们遵循的缩放比例。

enter image description here

我做错了什么?我已经将UIImageView s'contentMode设置为UIViewContentModeCenter,但正如您所看到的,它无效。请帮忙?我的完整代码如下。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"searchResultCell"];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"searchResultCell"];
    }

    // Get the Ad object that will be displayed in this cell.
    Ad *ad = (Ad *)[self.searchResults objectAtIndex:indexPath.row];

    // Set up the detail text on the right.
    cell.textLabel.attributedText = ad.attributedTextDisplay;
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;

    // Set up the image on the left.
    NSString *thumbnailURL = ad.thumbnailURL;
    NSData *data = [FTWCache objectForKey:[MD5 hash:thumbnailURL]];

    // If the image has been previously downloaded and is stored in FTWCache.
    if (data) {
        // Then use that data instead.
        cell.imageView.image = [UIImage imageWithData:data];
    } else {
        // Assign default image before beginning background image retrieval task.
        cell.imageView.image = [UIImage imageNamed:@"image_stub_ad"];

        // Trigger background task that retrieves the actual thumbnail from the URL.
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbnailURL]];

            // Proceed only with updating the table view cell if the returned NSData is not nil.
            if (imageData) {
                dispatch_sync(dispatch_get_main_queue(), ^{
                    // UPDATED: Added call to setNeedsDisplay.
                    UITableViewCell *theSameCell = [tableView cellForRowAtIndexPath:indexPath];
                    theSameCell.imageView.image = [UIImage imageWithData:imageData];
                    [theSameCell setNeedsDisplay];
                });
            }
        });
    }

    // UPDATED: Set the contentMode to UIViewContentModeScaleAspectFit instead of UIViewContentModeCenter.
    cell.imageView.contentMode = UIViewContentModeScaleAspectFit;

    return cell;
}

3 个答案:

答案 0 :(得分:0)

试试这个..

// Proceed only with updating the table view cell if the returned NSData is not nil.
            if (imageData) {
                dispatch_sync(dispatch_get_main_queue(), ^{
                   UITableViewCell *imageCell = [tableView cellForRowAtIndexPath:indexPath]

                    imageCell.imageView.image = [UIImage imageWithData:imageData];
                   [imageCell setNeedsDisplay];//this is the line I added only

                    [FTWCache setObject:imageData forKey:[MD5 hash:thumbnailURL]];
                });
            }

答案 1 :(得分:0)

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ImageViewCell *cell = (ImageViewCell*)[tableView dequeueReusableCellWithIdentifier:@"identifier"];

    if (cell==nil)
    {
        cell = [[UImageViewCell alloc] init]; //or from whatever way you generate this cell.

        //Manually set this below on each time the cell is newly created.
        cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
    }

    //Do the update of your imageView's image here 
    //( this is the update area when your cell is not nil 
    // and could be a reused cell.)

    cell.imageView.image = your_ui_image ;
    [cell.imageView setNeedsDisplay];

    return cell;
}

答案 2 :(得分:0)

不是一个完整的答案,而是一个"改进"在异步任务中触发远程获取:

    // Trigger background task that retrieves the actual thumbnail from the URL.
    [NSURLConnection sendAsynchronousRequest:request 
                                       queue:[NSOperationQueue mainQueue] 
                           completionHandler:^(NSURLResponse* response, 
                                               NSData* imageData, 
                                               NSError* error) {
         if (error) {
              [self handleError:error];  // connection failed
              return;
         }
         // here, at a minimum, check status code and Content-Type:
         // ... add code
         if (statusCode == 200 && contentTypeOK)  // "OK"
         {
             [FTWCache setObject:imageData forKey:[MD5 hash:thumbnailURL]];
             [tableView cellForRowAtIndexPath:indexPath].imageView.image = 
               [UIImage imageWithData:imageData];
         }
         else {
             // we didn't get an image, possibly other errors (e.g. authentication, etc.)
             NSError* err = ...;  // add code
             [self handleError:err];
             return;
         }
    }];

如果需要,此代码缺少可以取消的可能性。也无法阻止为同一图像启动多个请求。

上述问题以及某个用户场景可能会导致应用程序产生无限数量的正在运行的网络请求 - 这最终会导致应用程序因内存问题而崩溃。为了改善这一点,我们需要利用NSURLConnection实现与委托的异步样式 - 这使我们有机会取消请求,并采取额外的测量,不会调用多个请求。

编辑:

另一项改进是将图像数据插入到缓存中,并在后台任务上创建UIImage对象,后台任务的完成处理程序更新单元并在主线程上执行。 / p>