Strategy to cache / persist downloaded images in iPhone App - iphone

My app needs to download about 50 images from an online MySQL database which I'm maintaining. I know I can control the way they're cached using (for example):
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:aURL]
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30.0];
But:
1) does using this caching-policy mean the images will truly forever remain on the user's device after they've been downloaded the first time? OR,
2) am I better off manually saving them myself to the app's Documents folder (perhaps also concurrently writing a database to there to mirror the one online) to ensure their persistence - that way I can just load them from there (the device's Documents folder) from that point on, on all subsequent runs of the app?
Basically just need recommendation on the best way to persist the images on a user's device after their initial download - so the user always has something to look at in case connectivity issues are preventing them from being able to grab whatever new images have been added to the online database.
Any and all advice would be highly appreciated.

NSURLCache uses a memory and a disk cache for downloaded requests. I remember there being issues pre-iOS 5 which led to separate libraries like SDURLCache, but I don't think they're needed anymore.
Even with the disk cache, it may still be cleared out by iOS when space on the device runs short. If you don't want this to happen, you can store the images yourself in the Documents folder... but this situation is what the Caches directory is meant to be for. You download the images, they hang around unless the device runs out of space, in which case they're cleared and re-downloaded as needed. If I was a user of the app, I would prefer that behaviour over permanently taking up disk space for things that can easily be restored from the network.

Related

How to make iOS app cache ALL request responses?

I'm starting to work on an app which will include in quite a few places data that I will download from my server each time user is asking to view them. Then, when user opens app again without any internet connection, app should let him view any content it previously downloaded, just loading it from the cache. The point of this is that the content changes from time to time and user needs to be able to see the last downloaded version if he can't connect to the server.
Problem is, I can set the cache to a certain size on disk, but I have to store ALL the content no matter the size. I suppose I'd have to set cache disk size to make it bigger when it's running out of space. What is a good way to do this?
P.S. Not sure if this is relevant, but I was thinking about trying AFNetworking for this project (previously I used ASIHTTPRequest).
If you're using NSURLCache as an on-disk cache, you can check the disk usage with currentDiskUsage. If this is approaching diskCapacity, you can increase it using setDiskCapacity. You should perform this check before you attempt to write to the cache.
I have worked on same type of project, I used AFNetworking and according to me storing the data in local database is better option then caching it... and at the time when user starts app just have one service call which just checks the database version. If its old version replace database and handle the case if network fails by displaying the older version.

Is it possible to use only the HTML 5 application cache for a webapp?

I'm developing a webapp, which should even work if the iphone is offline. I used the HTML5 application cache to implement this feature.
But: can i force the webapp to use only cached elements? Cause if you have a poor internet connection, loading the app is pain, cause it loads all elements from the internet. If i could display cached files (e.g. big images), the loading time can be much faster.
Any ideas?
The web app will use cached elements unless it detects a change in the cache.manifest file. So as long as you don't update the file (it's bit by bit, so even a comment change will make it appear updated) the web app will continue to use the cached code/images/etc. as long as you explicitly list them in the CACHE section, unless you put them or directories in the NETWORK section.

HTML5 LocalStorage limit hit but I only use offline cache

I'm developing an offline web-app for a client of ours, designed to run on an iPad in airplane mode, mounted on a stand. It has no server-side dynamic pages, only a static HTML page, many JavaScript components to handle navigation and interactivity, and a bunch of small graphics assets. The whole website (static html + css + js + graphics) weighs exactly 8.3Mb.
I'm caching the whole site via an offline.manifest declared in my single HTML file, this manifest references absolutely all the files under the root directory, so that all files needed are cached.
I'm not using localStorage, IndexedDB or other offline-storage techs in my JS code. Apart from the "automatic" caching, I don't store anything on-device.
So atfer checking my webserver logs, when my client installs the webapp on its iPad homescreen, it downloads all the files once, then never downloads anything from my server afterwards. That's fine, exactly what he wanted in the first place : a full offline webapp.
Then, how comes that after several minutes of testing from my client, his iPad asks him to “increase local storage from 10Mb to 25Mb” ???
FYI, the app consists of a kind of quizz: one welcome screen, 19 question screens, one result screen ; the user can navigate backwards/forwards in the questions sequence, but they're created and nullified on-the-fly so as to minimize memory footprint. Anyway I don't believe this problem has to do with RAM access, only with "hard", permanent, cached storage.
I've noticed that with all apps, it's like the iPad has to realize it has everything, and waits a few seconds to realize that it's going to go over it's app limit.
it would be nice to have it default to a larger amount, or let you set it up with a larger amount to begin with.
Seems like my client doesn't have this problem anymore. As I'm not in direct, physical contact with him, I can't tell what he did to get rid of it.

Better way of updating images bundled with the app

In our iOS app we have close to a hundred image files in resources bundle. Now we want to make them network based since the images may change (updated/no longer needed/additions) at any time. We are debating at what approach would be optimal. From what I have read, I understand that the resource bundle will not be editable on the device. So, when I start the app, I will check from the server if there are any image updates. If so, I will download the changed images and then save them to documents directory. Then in the app, for every image, I will basically have to check if it is in the resources bundle, then grab it from there. Else pick it from documents directory and display it.
Another approach is I don't have anything in the resources folder, I download all images on app launch from the server and store them to documents directory and then on, download the changed files at subsequent app launch. Here I am eliminating the check on resources folder if an image is present or not and my app bundle size would be reduced.
The third approach would be to copy the files from my resources directory to the documents directory on first launch and thereafter continue from documents directory.
Any suggestions on what would be a better approach or all of them would be similar from the performance point of view?
IMO, option three offers the best balance between eliminating needless code and preloading as much data as possible. You don't want to make the user wait for 100 image downloads when the app starts the first time, so pre-load as many as possible. The copy code is simple and will only be used once. So that eliminates the runtime checks you'd have to do with the other options.
No worries, performance will not be an issue, unless you use a particularly unwise image lookup algorithm.
Filesystem traversal should be pretty fast for such a small amount of files.
Before implementing something yourself, I would recommend looking at something off the shelf for Image Caching. Namely EGOImageView from EnormEgo.
I have used it in several applications which are dependent on grabbing images from URLs. It handles everything for you, you just set up a 'background' image for it to show while it goes about it's business of grabbing the URL based image in the background. The second time you use it, it's available immediately. Definitely gets my vote for ease of use...
p.s. it's free to use

Managing iPhone app sandbox tmp directory size for caching images

I have a fairly image-intensive iPhone app, and I'm looking to store remotely downloaded images locally in the app's sandbox tmp directory to avoid unnecessary network requests. Is there a limit to the total size of the files stored in an app's directories, or does the app need to manage that? How would the app determine the size of the files in the tmp directory?
Also, if the app needs to manage the size of the cache, I'd like to implement some kind of cache policy to determine which files get invalidated. How would I go about doing this? If I want to implement a basic LRU caching policy - invalidating files that have been used least recently - it seems like I would need to store access counts for each image and store that on the disk as well, which seems kind of funky. I suppose an easy size management policy would be to simply completely wipe the cache each time the application terminates.
Also, what's the difference between using the directory from NSCachesDirectory versus NSTemporaryDirectory? The Apple docs mention both, but don't talk about which one to use for what type of files. I'm thinking the NSTemporaryDirectory is more like a Unix /var/tmp directory, and used for ephemeral data that can be wiped out at anytime. Seems to me the NSCachesDirectory is more appropriate for storing cached images, since the files could be needed across multiple app lifecycles.
All temporary directories are local to your application; any of them will work and there is no artificial limit to the size of their contents.
A persistent LRU cache policy should be both sufficient and relatively easy to implement.