How to make iOS app cache ALL request responses? - iphone

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.

Related

Syncing Database (sqlite) from WebService(Json/XML) for iOS

I have a Web Service and sqlite database. In this, web service will be used to store data inside database. Now I want to include sync functionality as - Whenever application starts at that time the database will start to load its table's data through web service.
Now after some time when I update my my web service the database will be updated accordingly. My question is that what are the best practices that I must follow for this update. Should I clear whole DB and start adding all rows again(I know this will take a lot time) but If not this then how do my database will add only particular data from the web service?
Thank you.
What I suggest you is:
store all your webservice content into db first when the app starts.
display your content on the screen from db only.
again when you need to refresh or recall your data just update the database.
Thus, you will always find all your fresh data into database.
Downloading and updating the entire server data will prove expensive. It will use more bandwidth and prove costly to your customer. Rather than pushing the entire load (even for minor update), send a delta. I will suggest you to maintain version information.
When application downloads the data from web service for a said version and store it successfully in the database, set the current updated version as well in the DB.
When app starts the next time, make a light weight header request to get just the version info from the server. The server should respond to this header request with the latest data version number.
Check the version from WS with the current application data version stored in the DB. If the server has an updated version, start the sync.
The version change information should be delta i.e.
For new version, server should send only the information that is changed since the version available with the device.
You server should have capability to calculate the delta between two versions.
Delta information will typically have sections like, new data, updated data, deleted data etc.
Based on this, the iOS app will make the necessary CRUD(Create, Read, Update and Delete) operations on the DB data.
Once the iOS app updates itself, then you can update the DB version to the latest received version from server. Until then let it remain dirty for proper error handling.
Hope that helps.
I would recommend you use RestKit's superb Core Data support.
By using RKEntityMapping you can map your remote objects from JSON or XML directly to Core Data entities in your database.
RestKit will automatically maintain the database for you, inserting and updating entries as appropriate from your web service. (In my experience, I've found deleting objects requires a tiny bit of extra work depending on how RESTful your web service is).
RestKit definitely does have a learning curve attached, but it's well worth it: having deployed it a couple of times now, is definitely a much better solution than manually writing your own SQLite/Web Service syncing code.
First you need to set all webservice content into your SQLITE.and what you want to display get that data from SQLITE.and perform opertaion into that sqlite table and when once all this done you need to changes made are saved it into webservice.
Follow this way.

Wireless updating in objective-c

I have an application in the store that has a bunch of UITableViews, each has a bunch of items that when selected, load a UIWebView that loads a local HTML file. The reason I do this is so it allows for viewing when there is no internet access, however it makes it tedious to update.
How would I go about both keeping local files, and keeping web files, so that If I update one on the web it would let the user know there is an 'update' and it can download and overwrite the old file with the new. Is this possible? Like I would make myself a backend to edit my HTML, and have a connection to the app so whenever I clicked save the app would know to ask the user to update the files so I don't have to submit to apple for such small updates.
But I still need to allow offline viewing in case they didn't have internet access.
What technologies or techniques would I have to research to accomplish this?
Thanks
what you're looking for is an html5 concept called application cache.. it directly addresses your problem. With app cache you can cache static content at the client side, which they can view even if they're offline, yet they can update it when the content on the server changes. If you look around you'll see people use this for the iPhone as well.
update:
What way would I go about rewriting files on the phone from ones on a server?
you basically update the cache to do that. from the docs:
The application cache automatically updates only if the manifest file
changes. It does not automatically update if resources listed in the
manifest file change. The manifest file is considered unchanged if it
is byte-for-byte the same; therefore, changing the modification date
of a manifest file also does not trigger an update. If this is not
sufficient for your application, you can update the application cache
explicitly using JavaScript.
I encourage you to do some reading on html5 local storage just to get the concept of local cache and manifest files etc, then just follow through the instructions on the apple docs.. It's not that difficult.
You can cache the content as abbood said but that won't allow you to provide initial offline content.
Another approach would be to use NSURLProtocol, which allows you to swizzle a request. For example, if you have a request for "http://google.com", you would be able to either change the URL or load your own content (say from a local directory).

how can I hold initial data when introducing an iPhone app?

I am developing an iPhone app which retrieves information via NSUrlRequest and displays through UIWebView.
I want to hold initial data (such as HTML pages, images) as a cache so that users of my app can access to data without network costs at the first time.
Then, if data on my web server are updated, I would download them and update the cache.
For performance issues, I think it is better to store data on file system than on core data.
Yet, I think it's not possible to release a new app writing data on disk.
So, I am about to store initial data(or initial cache) at Core Data, and when users launch my app for the first time, I would copy the data to disk (like /Library folder).
Is it, do you think, a good approach?
Or,...hmm, can I access to Core Data using NSUrlRequest?
One more question,
I might access to file system using NSURL, which is the same as to data on the Web. (right?)
My app would compare version of the cache with version of data on my web server, and if it's old, retrieve new data.
and my app will access only to file system.
All data are actually HTML pages including script, and images. And, I want to cache them.
could you suggest a better design?
Thank you.
Is it, do you think, a good approach? Or,...hmm, can I access to Core Data using NSUrlRequest?
No.
One more question, I might access to file system using NSURL, which is the same as to data on the Web. (right?) My app would compare version of the cache with version of data on my web server, and if it's old, retrieve new data. and my app will access only to file system. All data are actually HTML pages including script, and images. And, I want to cache them.
Yes.
But you could also be more clever. And by "more clever" I mean "Matt Gallagher." Take a look at his very interesting approach in Substituting local data for remote UIWebView requests.

Recreating core data at application launch

I have an app that connects to a website. I store its data as core data and then I use the core data to load my tableviews. I believe, I want to reload the data from the website every time I launch the app, since the user could change the data if they were to go onto the website.
What's the best way to approach this? Should I just delete the core data each time the app terminates?
It depends on how critical it is that data on the device always be current, on how long you expect users to wait before working with the app, and on what you want to happen if someone tries to use the app when the network is slow or unavailable. If you delete the store, and the app can't connect immediately, the user has no data. Even if the network is fine, the user still has to wait on network and server latency before they can start using the app. This is likely to be poor UX.
On the other hand if you allow data to persist after the app exits, the user's data might not be current, at least not at first.
If you don't ever want the data to persist after the app exits, an in-memory store might be the best choice, because it will never be saved to a file anyway.
If presenting potentially old data is OK either (a) briefly when the app starts up or (b) when the network is unavailable, a better choice would be to keep the data store but make new network calls to update the existing data. You could provide some sort of UI to indicate that updates are in progress. You might also have some in-app indication of when your app last synced with the server.
I'm not sure of how your application makes use of the Core Data stack, but if you don't care about (or don't have) changes made locally on the device, I'd say the easiest way to refresh the data from the server is just what you said: wipe out the store file, re-create it and import the data from the server. However, I wouldn't do this systematically on each application launch. Make sure the user knows about it and think of providing a "refresh" button to trigger that procedure. Also make sure you can download new content from the server, before wiping out the local store.
If you want to load all the data in memory (and also want to do updates) then you can create a managed object context backed by a NSAtomicStore persistent store subclass. In the NSAtomicStore subclass you can implement the read: (load: method) and the CRUD actions (newReferenceObjectForManagedObject:, save: and updateCacheNode:fromManagedObject: methods)

iPhone and HTML5 Cache Manifest

I am trying to build an iPhone web application using ASP.NET. The page is dynamically rendered once for each visitor. At this point the page can be bookmarked and it will never change again for that visitor. For this reason it should be cached locally from that point on so the application will run if referenced from the bookmark even if no network connection is available. No matter what I try the phone continues to request the page from the server forcing a re-render or it fails if the phone is offline.
Louis Gerbarg suggested in this post that I use HTML5 Cache Manifest to get this working however following the w3.org docs does not appear to work for the iPhone. Does anyone have a good example where application cache is working?
The cache manifest file has to be served with a 'text/cache-manifest' mime-type. This is absolutely critical, it will not work without it. If you navigate to the url of your manifest file, it should trigger a download...
Also, I've found that putting the manifest location in the tag as an absolute location, as well as all the entries in the manifest file to be more effective.
I answered your previous question related to this, but it was not clear from that question that you were trying to cache dynamic content. The cache manifest is for getting static content you want for offline web apps to work.
I am not sure you can do what you want. Do you want the app to be able to function offline, or are you just trying to peg something in the cache because it is slow to download? Unless you are actually constructing an offline webapp (which the user will add to as a bookmark or an app in the Spring Board) then your page can (and must necessarily) be evicted from local storage at the browsers discretion, regardless of how loose a cache policy you set on the page.
You should use the Safari Javascript Database API which should work for iPhone and Safari 3.1. It works great for local caching and data storage:
http://developer.apple.com/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/
It could be to do with the size of the output.
I can't talk from any serious experience in tweaking things specifically for an iphone, but there is an intersting read from the YUI team here: http://yuiblog.com/blog/2008/02/06/iphone-cacheability/, which indicates that the largest unzipped cache file that can be held in an iphone is 25k, and that for optimal caching, as many components as possible should be <25k.
That may be the cause of your problems, but that's only a guess.