recently i created a post: NSData caching routine
But, now i want to be more specific in what i'm asking.
You see, i have "carousel", that is actually a scroll view having 7 images. When it first appear, it load images from internet and auto scrolling.
My problem is, i don't want to images be loaded every time it scroll. Luckily, there is some "cache" mechanics worked in background. So, when it load all images, then terminate app, then launch in without internet connection, all images are set already, so, it somehow load it from somewhere.
There is the code i use:
NSError *error;
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@", WEBSITE, mdl.imageSubUrl]] options:NSDataReadingUncached error:&error];;
NSLog(@"data size0? %lu", (unsigned long)data.length);
And that is. You may want to try it by yourself, loading some image, then restart app in airplane mode and check bytes length. There will be data, even when i search for it, and there is said, that dataWithContentsOfURL
does not do any cache.
So, what i want is simply check, if there are data, and if it is, not download it. Something like this:
if (haveData){
self.ivPic.image = [UIImage imageWith:myData];
} else {
NSError *error;
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@", WEBSITE, mdl.imageSubUrl]] options:NSDataReadingUncached error:&error];;
NSLog(@"data size0? %lu", (unsigned long)data.length);
}
Unfortunately, i don't know how to make such test (if there is data). Secondly, i'm not quite sure how to load stored data, instead of dataWithContentsOfURL, which will launch loading from host.
If you were to do this yourself, you could create two-tier cache system, using NSCache
and local file system. So,
At app startup, instantiate a NSCache
object.
When you need to download an image, see if image is in NSCache
.
If not, see if image is in NSCachesDirectory
folder in file system, if found here, but not in NSCache
, make sure to update NSCache
accordingly.
If found in neither NSCache
nor NSCachesDirectory
, request it asynchronously from the network (using NSURLSession
) and if you successfully found image, update both NSCache
and NSCachesDirectory
accordingly.
BTW, upon UIApplicationDidReceiveMemoryWarningNotification
, make sure to empty the NSCache
.
That might look something like:
NSString *filename = [webURL lastPathComponent];
NSURL *fileURL;
// look in `NSCache`
NSData *data = [self.cache objectForKey:filename];
// if not found, look in `NSCachesDirectory`
if (!data) {
NSError *error;
NSURL *cacheFileURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
fileURL = [cacheFileURL URLByAppendingPathComponent:filename];
data = [NSData dataWithContentsOfURL:fileURL];
// if found, update `NSCache`
if (data) {
[self.cache setObject:data forKey:filename];
}
}
// if still not found, retrieve it from the network
if (!data) {
[[NSURLSession sharedSession] dataTaskWithURL:webURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
// handle error
return;
}
UIImage *image = [UIImage imageWithData:data];
// if image retrieved successfully, now save it
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.cache setObject:data forKey:filename];
NSError *fileError;
[data writeToURL:fileURL options:NSDataWritingAtomic error:&fileError];
});
}
}];
}
Having said all of this, I agree with the others that it's worth trying the UIImageView
categories found in either SDWebImage and/or AFNetworking. They might do what you need, with far less work.