I'm creating one iphone application that uses and xml to get some data from and a few images. Lets say that originally these files will be in the application bundle. But then I want to make my application to get updates from a web service. So lets say I download a new xml and new Images.
Where do I save them? I think I will be able to save them in the application "cache" right?
But then How do I make my application check if this resource exists in the cache, then load that one...else load the one in the application bundle?
iOS to be used 4.3 but if it makes it easier we can go to 5.
You will have to use NSFileManager to save the file to and load it from the document directory. Check out the following link, which actually contains all the info you need:
http://www.friendlydeveloper.com/2010/02/using-nsfilemanager-to-save-an-image-to-or-loadremove-an-image-from-documents-directory-coding/
If [UIImage imageWithContentsOfFile:fullPath]; (fullPath being the NSString with contains the path to your image in your document directory) returns nil, then the image is not present, so you'll have to load the default image from your bundle.
You can access your default bundle files using [[NSBundle mainbundle] pathForResource:#"yourFileNameHere" ofType:#"yourTypeHere"] This will return the path to your file in your bundle and you can just pass it to [UIImage imageWithContentsOfFile:]
This example only applies to UIImage, but you can easily adapt it to use other classes. I think the UIImage example is enough for illustrative purposes though.
You'll probably want to create a versioning scheme. After the app starts (or periodically) call the web service for a very cheap call to ask what version it has. You'll know what version you have (write in a plist or have the version number in the folder structure). Another options is pushing a notification.
The next thing you'll have to think about is how the app reacts to getting a new data set. You could do it only on start up but that might block the start up experience if you're bounding it to a web call. The other option is to allow the dataset to change while the app is open. You could have a model that uses NSNotificationCenter to notify your views and controllers that the data has changed. I would probably version the storage as well (folder per) to help with the transition.
As for how, you can make web requests with something like ASIHttpRequest, NSFileManager to write to the documents directory, and plists to save settings like version.
Related
I am able getting data from server and display on UITableView, It's working fine. But when I go to another tab and return to same tab it will call to server for data. I want to store data locally once get from server.
Please suggest me your thoughts.
Thanks!
You have to store the file on the device and this is possible in a few ways:
Store the files in the App its Documents directory
Store the files in the App its Library/Caches folder
Store the files in the App its Library/ folder
There are a few considerations for each option:
Files stored in the Documents folder are by default backed up by iCloud. You really have to think if this is necessary because you're eating up iCloud storage space from the user (for which he/she may pay).
Storing files in the Caches folder is a good way, but they may be deleted by iOS if the users disk is running low on space (therefore the name Cache).
Storing files in another (manually created) folder on the device will keep them as long as the app is installed. No iCloud backup or no removal by iOS
Getting the location of the specific folder can be done using:
[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
Where you have to replace NSDocumentDirectory by NSLibraryDirectory when you want the NSURL to the Library folder.
Storing data is as easy as creating an NSURL which points to the location where you want to store the data and then call the writeToURL:atomically: method on the NSData you want to store.
Converting UIImages to NSData can be done using UIImageJPEGRepresentation or UIImagePNGRepresentation.
i would prefer to use the HJCache library for the temporally store images.
For that followings are the reasons to implement the HJCache open source library.
Make it easy to use asynchronously loaded images in iOS apps.
Make it easy to use a shared file cache.
Make memory management ‘just work’ according to Cocoa norms.
Support typical cases of viewing images, eg scrolling through a list of tweets showing the tweeters profile pic, swiping through a photo album loaded over the net.
Allow the library to be used for other kinds of data too.
For more detail and tutorial visit the github and author blog
I have an app I'm designing that will allow for lots of PDF viewing. There are a lot of different languages available, and so if I were to include all of them in the app, it would be like 100+ mb in size which just won't fly.
So I'm thinking that I am going to put the pdf's on my server, and access them with a direct download link like this:
http://mysite.com/pdfs/thepdf.pdf
Which will return the exact pdf I want. So I'm wondering how I can go about accessing these resources as I download them on the fly?
I imagine I need to save the pdf's to the app resources folder? And then when a tableView row for the pdf is selected, I check if the pdf is in the resources folder (how do I do that?), and if not, pull it down off the server, and load it into my view?
I think I have an okay idea of what I need to do, just not very clear on the code to do it. Can anybody post the code for accessing the resources folder (if that's actually what I need to be doing), and maybe the code for how to check if something is in the resources folder?
Thanks!
Have you considered using a UIWebView to view the PDF instead of downloading and loading it yourself? UIWebView should take care of caching, so you won't have to worry about that.
Assuming that a UIWebView won't work, to download PDFs and see if they exist, you need to store it in the Documents folder. The resources folder cannot be altered after you submit your app to Apple, but the Documents folder in your app is completely fine. To access it, I would actually recommend ConciseKit, which can be found on GitHub. It gives you a helper method to access your app's document directory. The helper method is
[$ documentPath];
Then you can get the path for a file by doing
[[$ documentPath] stringByAppendingPathComponent:#"file.pdf"];
So that is how you get a path to a file, to check if it exists, you want to use NSFileManager.
[[NSFileManager defaultManager] fileExistsAtPath:#"path from above"];
I am planning to cache the images from a server and use show it as a sort slide show in my App. I would be asynchronously loading the images.
I have two options:
Either to cache the images as a File and use it whenever necessary.
Cache the images objects in memory and use it when ever necessary and write it in to files when Application quits.
Which one would be better?
Please let me know if you you have any kind of suggestions regarding caching images.
Your second approach has 2 major flaws:
If there's too many images then your application will get low memory warning and you'll have to dispose your images from memory anyway
It's also not a good idea to save all images to file on application quit - it is not guaranteed that your saving code will finish on application exit (e.g. if it takes too long system may just terminate your app and your images will be lost)
I'd suggest saving images to files right after you download them and keep in memory reasonable number of images you need to show without visible delay (loading extra images when required and disposing of unnecessary ones)
I would recommend you the first option. Leaves you more flexibility, e.g. when the data size increases the memory size.
I'd do it like this: Have a NSMutableDictionary with the cached images (as UIImage objects). If the image is not in the cache, look whether it's available as a file. If it's not available as a file, load it, put it into your dictionary and also write it to a file.
As for where to write the files to: you can either use the NSTemporaryDirectory() or create a directory inside your NSLibraryDirectory (use NSSearchPathForDirectoriesInDomains to locate it). The later has the advantage/disadvantage that it will be in the iTunes backup (whether that's an advantage or not depends on the use case). Using the Library directory is Apple's recommended way of storing data that is backed up but does not appear in the iTune's file exchange thingy (Documents directory).
I have started using EGOImageView to handle my caching; it's very versatile and handles the intricacies of caching for you.
It works very well for pulling images via http, you can find it on the EGO developer website here
http://developers.enormego.com/
For image caching solution on iOS platform, you might want to consider SDWebImage framework available at: https://github.com/rs/SDWebImage. It is very easy to integrate and takes care of all your image caching worries.: read more about the working here: https://github.com/rs/SDWebImage#readme
We recently picked this up for our app and it works great.
The iPhone application I'm working on comes bundled with 20MB of images in the application directory and I need to write new images to the documents directory over time.
Ideally I'd like to move the initial folder to the documents directory, copying the folder would mean wasting 20mb of the users disk space.
Failing that I'll create the required structure in the documents directory and leave the initial images in place, but that would mean checking in two places every time I want to display an image.
Is there a way of automagically searching the application bundle and documents directory when building an image path?
To answer your first concern: you can’t move anything out of the application bundle. Any modification of said bundle invalidates the signature and will render your app non-functional on all but jailbroken iOS devices.
Now, onto the challenge of copying images out: To find something in the main bundle, you’d do this:
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"myImage"
ofType:#"png"];
For an image, though, you’re better off doing this:
UIImage *imageFromBundle = [UIImage imageNamed:#"MyImage.png"];
That will do caching for you in a way that loading the image directly won’t.
I don’t know why you’d want to copy the image out, but it seems that maybe you have an initial set of images that may or may not be replaced. I’d recommend, then, instead of copying out of the bundle, look for the image first in the Documents folder, and if it isn’t there, copy it out of the bundle. That allows you to replace the images without copying from the bundle or modifying the bundle.
AFAIK the bundle is read only. So while your "move" idea is a good one, I am fairly certain Apple does not allow for it currently.
Is there a way of automagically
searching the application bundle and
documents directory when building an
image path?
I can say that I have done this for images but you have to create the magic yourself. I wrote a class that I would call with the name of the image as a parameter. That class would first look in the documents directory, then look in the bundle and finally look to a website for the image. When it found the image it returned the UIImage. A bit of a pain to initially setup, but once in place it is quite useful and I am glad I did it.
I have an iPad application that pulls in all of its data from an external web service. I am working on building in a demo mode that will use a cache of demo data stored on the device so it can be demoed and tried out without the web service connection (or an internet connection.)
Is there a project or good practices standard to follow to model this type of sample data? I'm expecting JSON arrays/Dictionaries back from my web service, how could I build a function that uses hardcoded data to create the NSMutableData object I'd expect to get back from a JSON web request?
I always stick sample data in a plist file in my resource directory. Obviously it can be created as, say, an array of dictionaries etc, and so can be loaded directly from file:
NSString *myFile = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"SampleData.plist"];
NSDictionary *myDict = [[NSDictionary alloc] initWithContentsOfFile:myFile];
Equivalent method exists for arrays. Obviously it might be slightly different format to your JSON array but ease of importing wins for me!
I did this for an app which is basically a front end to a WordPress web site. The app was designed to cache data to the Documents dir automatically, so prior to release, I just pulled out all the cached data I needed from the Simulator's directory for my app, put it in the bundle, and used the following logic:
If (network available ){
get new live data
}else if (have cached data from previous connection){
use it.
}else{
use data from the bundle
}
You might get some compiler errors if you try copy/pasting that into xCode...