In-Memory cache and DiskCache for Images Strategies - ios

Now, I am developing a news reader app like BBC news iOS.
see in BBC News
In my app, I must download image from server to and show it in view to make users easier to choose the news they want to read.
For more performance, I must cache image to avoid reloading image for server.
I know that there are 2 kinds of cache: In-memory cache that saving images in memory (RAM) and DiskCach that save images in Disk to load it when we need.
My question is:
What is best images cache mixed strategies for my App? (use both in-memory cache and image-cache)
My solution is:
download image --> save them in diskcache + save them in memory cache --> load image from in-memory cache on demand and show in view ---> in-memory cache over its MAX_SIZE --> free in-memory cache ---> load image from disk cache on demand and save it to memory cache --> repeat........
Is my solution is right approach?
Another question: when in-memory cache over its MAX_SIZE --> we will free its --> all images in cache will lose so image in our view will disappear.
--> How to solve this problem?
Sorry for poor English.
Thank in advance.

In one of my projects I implemented pretty much the same caching methods (Disk Cache and Memory Cache).
Maximum cache size
Each cache system had its own max size limit. The "size" of each image was computed differently in the cache systems.
For the memory cache, each image would have a size computed as
image size = image width * image height (in pixels)
So, the maximum size for the memory cache would represent a the maximum area of a pixel surface
For the disk cache, I used the actual file size for each file.
Making room
When using the cache systems, you might get to a situation where one of the caches is full and you want to insert a new item in it - you have to remove some items to make room.
What I did was assign a timestamp to each entry in the cache. Every time I access that item I updated the timestamp. When you want to make room, you just need to start removing items from the oldest to the newest based on the last access timestamp.
This is a simple algorithm for freeing up space and in some cases might actually behave poorly. It is up to you to experiment and see if you need something more advanced than this.
For example, you could improve this method by adding a priority value for each item and keep old items in the cache if their priority is high.
Again, it depends on your app's needs.
Expiration
For the disk cache, I would definitely add an expiration date for each entry. If the memory cache is destroyed when the user completely terminates the app, images in the disk cache might be stuck in there forever.
Encapsulation
Another aspect I would consider, is making the caching system as transparent as possible to the programmer. If you want to enable/disable one of the cache it would be best to have most of the code remain the same.
In my app, I built a central content delivery system and I would always request images from the internet through this object. The caching system would then check the local caches (memory / disk) and either return me the image immediately or make a request to download it.
Either way... I, as the "user" of the caching system did not care what was happening behind the curtains. All I knew is I made a request to get an image from an URL and I got it (faster or slower depending if the image was cached).

Related

ImageResizer .net for multiple product images perfomance issues?

I'm building an Asp.Net MVC4 Application with product pages. I have come by the ImageResizer Library for handling and serving the images. My page has jpg thumbnails 160x160px in dimensions and 3~5KB size each.
To my understanding using the ImageResizer library i could just upload the original large product image 600 x 600px & 10~20KB and resize it on the fly to the thumbnail size when the visitor requests the page. Something like:
<img src="#Url.Content("~/images/imagename?width=160&height=160")" alt="">
Which i understand is fine for a couple of images but my product page consists of 20 to 100 product jpg unique thumbnails (depending on pagesize).
Should performance hurt with processing on-the-fly 20-100 pics each time? Has anyone faced a similar scenario? I could always go back back and generate 2 different images (thumbnail and large) during the upload process but i'm very curius if i could get away with just one image per product and dynamic resizing.
When i say performance i mean that anything above 0.5 - 1s extra response time is a no-no for me.
In documentation it is mentioned, that there's caching plugin, which improves performance by 100-10000X:
Every public-facing website needs disk caching for their dynamically resized images (no, ASP.NET's output cache won't work). This module is extremely fast, but decoding the original image requires a large amount of contiguous RAM (usually 50-100MB) to be available. Since it requires contiguous, non-paged, non-fragmented RAM, it can't be used a (D)DOS attack vector, but it does mean that there is a RAM-based limit on how many concurrent image processing requests can be handled. The DiskCache plugin improves the throughput 100-10,000X by delegating the serving of the cached files back to IIS and by utilizing a hash-tree disk structure. It easily scales to 100,000 variants and can be used with as many as a million images. It is part of the Performance edition, which costs $249. The DiskCache plugin requires you to use the URL API (read why).
http://imageresizing.net/plugins/diskcache
http://imageresizing.net/docs/basics
When it comes to websites, every operation that can be cached should be. This allows the server to deal with more visitors rather than more processing.
You could either use the caching plugin for ImageResizer, or manually write to file using a certain filename, e.g.: product_154_180x180.jpg where 154 is product id, and 180 is the width and height, then check for whether it exists when you want to display it.
If you do the latter, you may be able to use the server to manage this for you, by linking to the expected filename in the page source, and if it doesn't exist, the server then calls a script that resizes and writes the resized image to disk using imageresizer.
This last method will also avoid the call to ImageResizer saving you some processing power.

Caching locally created images on iOS for fast reuse

I have a method in my app that builds UIImages with specific colors. Since most likely the same colored image will be created multiple times, I would like to cache that UIImage, then use the cached version rather than building a new one if that specific color is needed.
This is NOT caching of remote images from the web, these are locally created images.
What is the best method to do this? From disk or just save the UIImage objects into an NSDictionary? What about NSCache?
** I would prefer not to have to use library for this. Looking for a simple solution.
It depends how many images you have and how frequently and concurrently each is used.
If you have a set of images which are all used frequently then NSDictionary is a good choice as it will keep all the images in memory. If you do get a memory warning you can always remove all of the images and then regenerate them when required.
As you're generating the images in code it seems like caching to disk won't be so useful, but that depends on how complex the images are. Again NSDictionary can be used for an in memory cache, then fail out to disk if nothing in the dict, then recreate if all else fails.
The NSCache route offers you some multi-threading benefits (if you'd use them) but is generally similar to the NSDictionary route. You have a little less control as the memory management is handled for you so it's possible that the cache could decide to destroy some of your images more frequently than you might if you manage it explicitly.
In any case you only need a handful of lines on top of your current generation code.

What happens if NSURLCache is full?

I'm using default NSURLCache to cache images in my iPhone app.
What will happen if the cache is full and i'll try to cache another image?
Will it not cache the image? or it will be replaced with the oldest image cached?
Thanks alot
The maximum cache can be influenced with the initialization
initWithMemoryCapacity:... diskCapacity:... diskPath:..]
The new file will always be downloaded. (except when it's bigger than the maximum memory capacity, then it will just be downloaded and not saved in the cache)
If the maximum cache size is reached other file(s) will be removed.
It is not specified what files will be removed.
It's not difficult to create your own NSUrlCache and handle it yourself.
if you want to see a sample how to do that, then have a look at https://github.com/evermeer/EVURLCache

CALAyer vs CGLayer confusion: manipulating and saving images in the background

im pulling in images from the net, and want to manipulate them a bit such as adding perspective with CATransform3D, and compositing a couple together. After im done, I would like to save the file in memory so they can be pulled up when needed (like in a tableview cell for example). I managed to extract the image from the web, and manipulate them by making a CALayer. After a bit of reading, im a bit confused as to how to properly do this since these images arent displayed until needed and I obviously would like to do my work on a worker thread so the system wont lag. What would the best procedure be?
Apple recommends that you almost never try to cache images yourself since they cache them internally and you can be guaranteed that the cache will function properly even under high memory pressure.
You can cache an image using Apple's internal cache via the setName: and imageNamed: methods`. Furthermore, you should save a local copy of the image to disk in the caches directory so you dont need to download it again if the cache gets cleared.
So, in summary, use imageNamed:, if that is nil check the disk cache directory, if that is nil download the image. Caching a CALayer will make sooo much dirty memory,

Generate thumbnail images at run-time when requested, or pre-generate thumbnail in harddisk?

I was wondering, which way of managing thumbnail images make less impact to web server performance.
This is the scenario:
1) each order can have maximum of 10 images.
2) images does not need to store after order has completed (max period is 2 weeks).
3) potentially, there may have a few thousands of active orders at anytime.
4) orders with images will frequently visit by customers.
IMO, pre-generate thumbnail in hard disk is a better solution as hard disk are cheaper even with RAID.
But what about disk I/O speed, and resource it need to load images? will it take more resource than generate thumbnails at real-time?
It would be most appreciate if you could share your opinion.
I suggest a combination of both - dynamic generation with disk caching. This prevents wasted space from unused images, yet adds absolutely no overhead for repeatedly requested images. SQL and mem caching are not good choices, both require too much RAM. IIS can serve large images from disk while only using 100k of RAM.
While creating http://imageresizing.net, I discovered 29 image resizing pitfalls, and few of them are obvious. I strongly suggest reading the list, even if it's a bit boring. You'll need an HttpModule to be able to pass cached requests off to IIS.
Although - why re-invent the wheel? The ImageResizer library is widely used and well tested.
If the orders are visited frequently by customers, it is better to create the thumbnails ones and store on disk. this way the webserver doesn't need to process the page that long. It will speed up the loading time of your webpages.
It depends on your load. If the resource is being requested multiple times then it makes sense to cache it.
Will there always have to be an image? If not, you can create it on the first request and then cache it either in memory, or more likely a database, for subsequent requests.
However, if you always need the n images to exists per order, and/or you have multiple orders being created regularly, you will be better off passing the thumbnail creation off to a worker thread or some kind of asynchronous page. That way, multiple request's can be stacked up, reducing load on the server.

Resources