質問

Using AFNetworking 2.0's method setImageWithUrl, I set an image in an imageView located in a UITableViewCell. It works fine when the image displayed is first downloaded and then set. If, however, the image is available locally (has been cached) when it's set, there's a quick white flash before it is displayed.

Do you know how to avoid this?

Steps to reproduce:

  1. Set image (image will be cached)
  2. Close application
  3. Start application
  4. Set (the now cached) image

Code for setting the image:

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

    myCell *cell = (myCell *)[tableView dequeueReusableCellWithIdentifier:@"imageCell"];

    [cell.myImageView setImageWithURLRequest:[NSURLRequest requestWithURL:myImageUrl] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
        cell.myImageView.image = image;

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
        NSLog(@"Failed");
    }];

    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;  
}
役に立ちましたか?

解決

If anyone's bumping into the same issue, here's how I solved it:

In the success block, replace

cell.myImageView.image = image;

with

if (request) {
    [UIView transitionWithView:cell.myImageView
                      duration:0.8f
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{[cell.myImageView setImage:image];}
                    completion:NULL];
}else{
    [cell.myImageView setImageWithURL:myImageURL];
}

Voilà, no more ugly flashes!

Credits to this answer for leading me to the right track.

他のヒント

It seems that your issue is related to cell reusing rather to the caching issue.

When your cells are reused (when scrolling the UITableView or reopening the app) they hold a reference to the old image. And when you pass nil to the placeholderImage parameter, AFNetworking does not resets your image. Here is the source code. So the new image is set in a success block. But this block may be called after a slight network delay making your image to flash. By the way, you may omit the success block so the AFNetworking will set the image by itself.

If you don't have a placeHolder image you should set the myImageView.image to nil before trying to set a new one asynchronously.

In addition you should check if the dequeueReusableCellWithIdentifier: method returns a cell, and if not, create a new one. This may happen when the UITableView is created for the first time.

Here is an example:

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

    myCell *cell = (myCell *)[tableView dequeueReusableCellWithIdentifier:@"imageCell"];

    // Check if reused cell was returned.
    // If not create a new one, otherwise, reset the state of the reused cell
    if (!cell) {
        cell = [[myCell alloc] init];
    } else {
        cell.myImageView.image = nil;
    }

    [cell.myImageView
        setImageWithURLRequest:[NSURLRequest requestWithURL:myImageUrl]
        placeholderImage:nil
        success:nil
        failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
            NSLog(@"Failed");
        }];

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;  
}

You need a function like this:

BOOL ImageDataHasPNGPreffix(NSData *data) {
NSUInteger pngSignatureLength = [kPNGSignatureData length];
if ([data length] >= pngSignatureLength) {
    if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData]) {
        return YES;
    }
}

return NO;
}

then when you save your data, you need to choose the right way to cache

//Saving data
if ([imageData length] >= [kPNGSignatureData length]) {
    imageIsPng = ImageDataHasPNGPreffix(imageData);
}

if (imageIsPng) {
    data = UIImagePNGRepresentation(image);
}
else {
    data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top