简体   繁体   中英

How to show Image in UIImageView from cache using AFNetworking?

Here is my code how to download image from URL and save it into document directory using AFNetworking.

Now, my question is if image is already downloaded from URL then image is loaded from cache instead of re-download it. I want to do this using AFNetworking. I know that the solution for this problem is inside #import "UIKit+AFNetworking/UIKit+AFNetworking.h"

If anyone have any idea of how to help, please help me solve my issue.

#import "ViewController.h"

#define URL @"https://upload.wikimedia.org/wikipedia/commons/e/ec/USA-NYC-American_Museum_of_Natural_History.JPG"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.progressBar.hidden = YES ;
    self.lblProgressStatus.hidden = YES;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)Action:(UIButton *)sender
{
    self.progressBar.hidden = NO ;
    self.lblProgressStatus.hidden = NO ;
    self.ActionDownload.enabled = NO ;

    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

    NSURL *strURL = [NSURL URLWithString:URL];
    NSURLRequest *request = [NSURLRequest requestWithURL:strURL];

    NSProgress *progress;

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:&progress destination:^NSURL *(NSURL *targetPath, NSURLResponse *response)
        {
                NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
                return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
        }
        completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error)
        {
                [self.progressBar setHidden:YES];
                self.lblProgressStatus.text = @"Download completed" ;
                NSLog(@"File downloaded to: %@", filePath);

                NSString * strTemp = [NSString stringWithFormat:@"%@", filePath];
                NSArray *components = [strTemp componentsSeparatedByString:@"/"];
                id obj = [components lastObject];
                NSLog(@"%@", obj);

            NSString *docPath = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
            NSString *strFilePath = [NSString stringWithFormat:@"%@/%@",docPath, obj];

            BOOL fileExists=[[NSFileManager defaultManager] fileExistsAtPath:strFilePath];

            if (!fileExists)
            {
                NSLog(@"File Not Found");
            }
            else
            {
                UIImage * image = [UIImage imageWithContentsOfFile:strFilePath];
                self.imageView.image = image ;
            }
            [progress removeObserver:self forKeyPath:@"fractionCompleted" context:NULL];

        }];

    [self.progressBar setProgressWithDownloadProgressOfTask:downloadTask animated:YES];
    [downloadTask resume];

    [progress addObserver:self
               forKeyPath:NSStringFromSelector(@selector(fractionCompleted))                  options:NSKeyValueObservingOptionNew
                  context:NULL];

}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"fractionCompleted"])
    {
        NSProgress *progress = (NSProgress *)object;
        int temp = progress.fractionCompleted * 100 ;
       // NSLog(@"%d", temp);
       NSString * strTemp = @"%";

        dispatch_async(dispatch_get_main_queue(), ^{
            // Update the UI
            self.lblProgressStatus.text = [NSString stringWithFormat:@"%d %@", temp, strTemp];
        });
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

@end

You can download the image using this method defined in UIImageView+AFNetworking :

[imageView setImageWithURL:[NSURL URLWithString:URL] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
    if ([[extension lowercaseString] isEqualToString:@"png"]) { 
        [UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"png"]] options:NSAtomicWrite error:nil];
    } else if ([[extension lowercaseString] isEqualToString:@"jpg"] || [[extension lowercaseString] isEqualToString:@"jpeg"]) {
        [UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]] options:NSAtomicWrite error:nil];
    }
} failure:NULL];

The success block will be called even if it gets the image from cache. Hope it helped!

It uses cache by default. To test, go to a url you have access to of an image, then delete the image, and load again, and you'll see it's cached :D The images sometimes are not cached if they're big images.

If you want to increase this cache size, put this in your app delegate:

[[NSURLCache sharedURLCache] setMemoryCapacity:(20*1024*1024)];
[[NSURLCache sharedURLCache] setDiskCapacity:(200*1024*1024)];

EDIT RE: comments:

If you're looking to only download images once to your documents path, then perhaps the best way to test if an image already exists and should be downloaded or not is a test you can create. Eg, if the last path component (the last part of an image file path) of an image exists already in your documents, don't download it, else download it.

EDIT: further comments

Inside UIKit+AFNetworking/UIImageView+AFNetworking.h

/** Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. By default, URL requests have a Accept header field value of "image / *", a cache policy of NSURLCacheStorageAllowed and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use setImageWithURLRequest:placeholderImage:success:failure: @param url The URL used for the image request. */

- (void)setImageWithURL:(NSURL *)url;

This looks exactly like what you're looking for

to use:

#import <AFNetworking/UIKit+AFNetworking.h> 

and use

NSURL *strURL = [NSURL URLWithString:@"http://www.example.com/image.jpg"];
[imageview setImageWithURL:strURL];

I recommend you to use this library https://github.com/rs/SDWebImage

So, you can do something like this:

- (void)loadImage:(NSURL *)url
{
    __block UIImage *image = [[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString]];

    if(!image) {

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        [request setTimeoutInterval: 30.0]; // Will timeout after 30 seconds
        [NSURLConnection sendAsynchronousRequest:request
                                           queue:[NSOperationQueue currentQueue]
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

                                   if (data != nil && error == nil) {

                                       image = [UIImage imageWithData:data];

                                       NSData *pngData = UIImagePNGRepresentation(image);
                                       [[SDImageCache sharedImageCache] storeImage:image imageData:pngData forKey:[url absoluteString] toDisk:YES];
                                   }
                                   else {
                                       // There was an error, alert the user
                                       NSLog(@"%s Error: %@", __func__, error);
                                   }
                               }];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM