Xcode iOS Image Caching - ios

I am fetching images from my server and need to store them on the disk. I was wondering what is the best way to cache these images to prevent excessive requests and traffic. From doing some research it seems that there are many options available but I am not sure which to use.
Core Data
Store in the Cache Resources Folder in the file directory
After storing these is it best to use a NSCache class to put these data into memory for quick access or is Core Data quick enough?

Based on my experience, you could use SDWebImage, which caches the images you request based on their url, so the next time you "request" it, it will check if it is in cache, if so it won't make the request and it will load it from it instead.
I'm not sure why would you need to store the image, maybe you could tell us the reason and see if we can help any further.

I've had great results using FastImageCache by Path.
What Fast Image Cache Does
Stores images of similar sizes and styles together
Persists image data to disk
Returns images to the user significantly faster than traditional methods
Automatically manages cache expiry based on recency of usage
Utilizes a model-based approach for storing and retrieving images
Allows images to be processed on a per-model basis before being stored into the cache

Related

Should i save images to local storage in iOS App?

I am working on a project where i want to make the data, text, images available in offline mode as well.
I fetch data from a web-service which includes image urls and other data. I store the text data in core data entities, however i don't save images locally but fetch them in realtime.
To view images in offline mode i will have to save them to local storage. However i am wondering if it would be the right approach. Saving images to local may possibly eat up a lot of storage on user's device.
What is the best approach to address this problem?
Should i save images to local or should i fetch them on run time only?
Use NSCache. With NSCache you can set a limit to how many images and so on are cached. See Apple's documentation for more details: https://developer.apple.com/reference/foundation/nscache?language=objc
Edit:
Never mind NSCache, just save the images as files. NSCache can still save you network usage and allow your app to be more responsive, but it is not what you want.
Should i save images to local or should i fetch them on run time only?
This question for you , you should decide what you need or what is will be more suitable for your app . at any way if you want to cache images i suggest to use this library SDWebImage

iOS - Best practice to save Images locally - NSCache vs Save in Document Directory

I'm developing an app that similar to Instagram feed (tableviews with cells that contain images and some labels).
For all the data I'm getting from the database, I'm using Data Task (because it doesn't take much to receive them), but for the images (which their url's I get with the Data request), I need to save locally for future use (improve user experience).
My logic is the following:
Save in NSCache or in Document Directory, the images inside folder with the date they been downloaded(create it once and append all other images if needed) (I'm deleting every folder which is not from the recent 7 days), and then for the TableView, just load if from there, so the tableview will scroll smoothly and won't load the url directly from its delegate method.
So where is the better place to store them according to my needs, NSCache or Document Directory.
Looking forward to hearing your suggestions, Thank you!
NSCache and persistent storage serve largely different purposes. NSCache holds the item in memory and is used for optimal performance. But it takes up memory (RAM) and you really should make sure that if you use NSCache that you respond to memory warnings and purge the NSCache in those cases. And when the app terminates, the NSCache is lost.
Using persistent storage cache (generally the Caches folder) is used for a different purpose, saving you from needing to re-retrieve the asset via some network request, but not holding the resource in memory. This makes it a great cache mechanism across sessions of running the app or in situations where you may have encountered memory pressure, purged the NSCache, but didn't want to re-retrieve the asset from the network.
Note that I mention the Caches folder for persistent storage, whereas you seemed to presume that one would use Documents folder, but there are two considerations:
Apple is getting more particular about apps only using Documents folder for user data that cannot be easily recreated, and using Caches folder for data that is easily re-retrieved. See File System Basics for more information.
Starting with iOS 11, you should only store user visible documents in the Documents folder (see WWDC 2017 Fall video, iOS Storage Best Practices). Even if you had internally used files that were not easily reconstructed, unless the intent was to eventually expose the user to them, you'd use the Application Support directory, not the Documents folder.
Bottom line, one would generally use the Caches folder for a persistent storage based cache.
Note, we'll often use a two-tier cache mechanism. Cache the resource to both NSCache and the Caches folder. Then, when you go to retrieve a resource, first check NSCache (really fast), if not there, check persistent storage, and if not there, re-retrieve the asset from the network.
Having said all of that, to make it even more complicated, there is a third type of cache, that provided by NSURLCache (i.e. responses for network requests are transparently cached by NSURLSession and NSURLConnection). This cache is dictated by poorly documented rules (e.g. it won't cache any single item whose size exceeds 5% of the total cache size) and is subject to the HTTP headers provided by the network response. This cache, though, operates largely transparently to you and provides both memory and persistent storage caches. Often you can enjoy NSURLCache caching behavior with absolutely no intervention on your part. It's seamless (when it works).

Storing more number of images in file on iOS

I want to develop the solution where storing of image data downloaded from server and display it.
Scenario is, There will be thumbnail images placed on each row, clicking on that will download the actual image from server and display the image in a bigger view.
I want to store this image data once its downloaded from server, so that in the later stage if the same thumbnail has clicked to open, I don't need to again download the actual image from server, instead I can pull that from the place where I stored locally.
There will be more than 80 thumbnail images placed in rows and corresponding bigger images on the server.
Can I store the image data in a file and store it in documents directory or some thing like that? My worry, if the user selected all the 80 thumbnail images, then i'll have to store all the 80 bigger images locally on the app.
What is the best way to achieve this storing solution? Please advise.
Thank you.
You can store the images in the documents folder, as you already said. Just make sure to exclude them from backups, Apple will reject you for storing too much replaceable data in there.
There are also some third party image cache libraries, most notably (afaik) FastImageCache from Path:
https://github.com/path/FastImageCache
From their website what FastImageCache does is this:
Stores images of similar sizes and styles together
Persists image data to disk
Returns images to the user significantly faster than traditional methods
Automatically manages cache expiry based on recency of usage
Utilizes a model-based approach for storing and retrieving images
Allows images to be processed on a per-model basis before being stored into the cache

Should I save my images in Core Data or should I use SDWebImage

I have been developing an app with cloud/server data source. So naturally the process is one thing at a time. So at present, to fill my tables, I query the server which returns an array. The array contains urls to images and then from the urls I load the images using SDWebImage.
Now I am entering the stage of development where I need to implement Core Data for all the data in my tables (i.e. texts and images). So far I am considering the following approaches:
I can load the array from the server into core data (imagine properties as: firstName, lastName, photoUrl, shortBio) and then pass the photo url from core data to SDWebImage to display the image in the table cells. OR
I can load the array and the image into Core Data (i.e. load the array into core data in the background and then for each row, load the image into core data)
Of course the point here is that if I use SDWebImage it will save the image in its own caching system, which from my limited understanding may or may not be entirely consistent with what is in core data. On the other hand I don't understand core data enough to know if it handles saving images well in terms of performance (i.e. knows it's an image and therefore handle the file linking).
So What is the best way to do this? Can SDWebImage work in harmony with Core Data? Or is SDWebImage redundant since core data is good enough all by itself?
Another thing to note is that presently, my data loads from server immediately and then the images come as SDWebImage loads each into its UIImageView. This may not be a problem with Core Data since ideally the image will be in the local DB. Any thoughts?
Based on your question and comments, it seems you are trying to locally cache images that were retrieved through an HTTP request.
The URL loading system is already caching the images. There is no need to implement another layer of caching on top of that, wether it be SDWebImage or CoreData. When an HTTP response is received from the server, the server includes "freshness" information that informs the client how long and under what conditions that response is valid. The URL loading system, by default, obeys those rules. You can check the freshness information of responses using a tool like Charles or REDBot. The server is the only party in this conversation that can know how long a response is valid for.
The URL loading system does not, by default, cache to the filesytem - only in-memory. This is easy to change:
cache = [[NSURLCache alloc] initWithMemoryCapacity:(1024*1024*512) diskCapacity:(1024*1024*1024 * 100) diskPath:#"Cache.db"];
[NSURLCache setSharedURLCache:cache];
Or when using NSURLSession:
cache = [[NSURLCache alloc] initWithMemoryCapacity:(1024*1024*512) diskCapacity:(1024*1024*1024 * 100) diskPath:#"Cache.db"];
[sessionConfiguration setURLCache:cache];
session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
Storing image data in Core Data is something in general to be avoided, at least with the NSSQLiteStoreType persistent store. Even small images are large in the SQLite database and cause fragmentation, etc. that impact performance. If you are going to store image data in Core Data, it's preferable to use external storage - either by use Core Data's own external records storage, or by storing image data on the filesystem and referencing it in managed objects by using URLs.
However, if you are using Core Data OR SDWebImage to "cache" images, you are ignoring the freshness information that was returned in the server's response unless you implement your own validation layer - which the URL loading system is already doing for you!
Regardless of the question semantics, I think you need some more hard information to inform your decision.
It would be useful for you to know that storing large images (larger than, say, thumbnails) is not recommended and will lead to performance issues. Core Data has an option for large data where you can check "Store in External Record File". Alternatively, you can administer your own cache data (in this way you can flexibly update the images via download on a per-need basis on each device sharing the same data). The accepted best practice is to only store the image URL in Core Data (typically relative to the application directory) and handle the file storage / display separately.
I do not know SDWebImage, but this might provide some of the functionality that you need in the light of the above.
I hope this helps you make your decision about the data architecture.

Loading images from AppBundle vs. CoreData

I'm making a catalog where the cells in my collection view will be either an image with a label or a pdf. There will be many collections and they themselves will be static. I want the user to be able to save the cells he likes and view them in his own custom view.
1) I could to store the image as data in Core Data.
2) I could just include the image in my App Bundle and load the image from there every time my app starts.
I've got it into to my head that reading data from a Core Data Store would give me more options when building my app as well as offer some boost in performance as opposed to reading it from the app bundle. Is that true? Keeping in mind of course that most of the data is static.
It seems inefficient to have images both serialized images in my app bundle and the pure data as well.
I think I'd rather have it all in the store but they have to be loaded from the bundle at some point in code right?
I'd love to know how other developers do it.
Now in Core Data there is an "allows external storage" option for binary data, which basically means if your file is bigger than 1 MB it will be stored automatically outside of your database, and you have to do nothing differently. In my opinion that's the way to get the best of both worlds, increased performance + automatization + fast queries (although they are slower than usual when you allow external storage, but still faster than doing it yourself)

Resources