I am wondering why storing user profile images as Data to user defaults is ill advised. The reason being: I have already created an app that has some people using it. The app requires that users create a profile, on which they can upload up to 6 profile pictures. The images get pushed to my back end and also are stored as Data to the app's user defaults.
I've read that it is better to save these images to the document directory and save the file path as a string to user defaults. Why is this exactly? Is it such a big deal that I should take the time to write code that will convert images saved as Data to user defaults on already existing devices to images saved to the document directory?
The "why" is easy. The UserDefaults is not a database. It's just a plist file. Either the whole thing is loaded into memory at once or it isn't. If it is, there are all your UIImage data objects sitting in memory. Memory is limited and images are big. Plus you waste time during loading and saving.
The "is it such a big deal" part is a matter of opinion. In my own opinion, yes, it is. That's because I've gone through this process, and I was glad I did. Yes, it's a pain writing migration code, but once you've done it you just leave it in place and your app is now handling data saving correctly forever after.
Related
I'm making an app where the user can take a picture and add a title and description. But now I need to store the picture and the titles. I’ve tried making an object that contains title, description and image properties.
When it’s done I save an array of custom objects with the information on it with UserDefaults. My idea is showing in another view a table view with all the content and pictures the user has taken on the cells. I tried getting back the information with user defaults. It was working well until the user saves too many pictures. When the viewController with the tableview loads, then my app gets slower, and eventually it crashes.
I suppose the problem is when I load all the array with all custom objects, all the pictures are loaded into memory although they aren’t used and displayed for users. So I think it isn’t the best way to make what I want to make.
Is there any way better to make what I’m making or store data more efficiently and use it in tableview without using all the memory of the device?
I’m making the app from 0 again.
Can you show me how to store data and images efficiently?
There are several options for permanently storing user data on the device such that it will survive app and phone restarts. NSUserDefaults typically is for small amounts of data, such as user preferences.
When it comes time to store a lot of data, in particular big binary objects like photos, you need to decide which design you want to use. One option:
store all the photos in one directory in your apps documents and then use some simple lookup store (perhaps Core Data, or SQLite, or even a flat file) to index the photos and their metadata. Or if you don't care about indexing you can read the list of file names from the directory and sort them by time.
The other problem you are maybe having is that you are trying to load all of the photos at once for the user. As you have discovered, once you have more than a handful of photos this system falls apart. You need some mechanism to load only a few photos at a time, preferably only the ones the user needs to be displayed at that moment.
So, for example, if you are displaying the photos in a tableview, you want to only load the 10-15 photos that are visible in the table at any given time.
When storing this kind of data, you have 2 options (In fact you have more than 3 options, but saving image to the disk is IMHO complicated for this.) -
UserDefaults
Database like CoreData/Realm/FireBase...
The first one is recommended when there is not much data to save... For operating with more data, I would use database - CoreData...
For you operation you can use CoreData and NSFetchedResultsController (which is designed especially for fetching objects from the database)...
you can read the FetchedResultsController doc here... and core data basics here
Wish you best luck!
I have a social app, where the user can like photos... So, in order not to wait for fetching the data from the server, I want to store to the device, an array of strings, containing the photos' objectIds.. The question is, considering the user can like thousands of photos, is it good practise to use UserDefaults to achieve that?
EDIT
As pointed out by Eric Aya in the comments, NSUserDefaults aren't loaded automatically into memory when the app launches.
NSUserDefaults are loaded into memory when your application launches If you have a particularly large amount of data stored in NSUserDefaults then the time it takes your app to launch to load NSUserDefaults will be impacted by the amount of IO required to retrieve your data. The intended use case for NSUserDefaults is to store small sets of data such as default user settings.
A Plist may be a better solution (NSUserDefaults is just a Plist, the difference being is it's loaded automatically for you when the app launches). You will still have the same issues with load times when you decide to grab the Plist as you will be loading a file (the Plist) into memory. You will be able to handle this with something like a progress bar or an activity indicator which gives the user a nicer experience. than having to wait longer than usual for an app to open. CoreData is another option (usually intended for more complex data structures than strings, on the flip side it gives you the capability to scale your storage needs very easily if the complexity of your data increases), there's a fairly steep learning curve involved but it's a wonderful feature and is well documented by Apple: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/
I would also recommend storing the data on a server where you could expose it via an API and cache the response using a Plist/CoreData/Whatever you like. This way if your users change devices they will still have access to the same data as it's stored remotely.
Good luck!
I want to store some photos that I take from a web service to my phone for the case when I don't have internet connectivity. I am storing data to a database but i have a question: should I store in the database the URL of the photo and the photo in a folder, or store the image in the database? The volume of photos shouldn't be great; something like 200-300 small pics, at approx 30-40kB each.
If you already have a database, i would organize my photos in database with only the path to the photo. And the photos can be stored on memorycard or on local disk.
The basic rule of thumb is to put big data objects like images right onto the disk and only reference the URLs. This might come in handy for loading/processing the images anyway.
30-40 kB per image is not that much, but then I'd consider 6-12 MB for the database quite extensive, especially it's probably the majority of your database volume.
I'm not real familiar with iOS. But my understanding is that it supports XML files. If the database is just being used to store the paths (instead of images), why not use an xml file to store the paths?
If you need the db, with small images, I don't see it being a problem if the phone is just using it. Either way, I don't think it'll be an issue. Someone else can probably give you a better answer as far as efficiency. That's outside my jurisdiction.
Store all the pics in document folder, and when there is no internet connection get them from document folder of your iPhone.
I have created an app which displays information in a organized manner about cultural places.
The information is subject to changes, so I want it to be downloaded from the web. But not everytime. Only once in a while, because information doesn't change often.
What I want to do is, the first time the user opens the application, it downloads all data from the web. For the moment, I parse it from an xml (which is about 100Ko), and I get a NSMutableArray of "CulturalPlace" objects. but it is very slow. And what I would like to do is, to store this data locally (in case the user has an iPod touch an is not on a wifi, or if he is on EDGE and does not want to redownload all). So the user updates data only by clicking an "update button" on the top right of the screen. Otherwise it reads it from disk.
I really don't know what could be the best solution. I thought about Core Data, but I have several Tableview imbricated (Rootviewcontroller > ListofPlacesViewController > PlaceViewController) and I really cannot find good tutorial for a simple use like mine. (the iTunes "TopSongs" sample code seems too complex).
I thought also about not parsing the xml, but instead try an NSURLConnection and get a plist file. But I never managed to read anything from the local file.
So my main question is, should I keep the xml parsing method, or should I use another format to tranfert the data from the web? And what is the best way to store and read data like an NSMutableArray of custom Objects ?
Thanks in advance for your help, sorry for my approximate english.
You could use HTML5' localStorage. It's supported by Chrome and FF on the PC and Safari on Mac OS and iPhone (to the best of my knowledge). It acts like a local database. Bear in mind that if the user selects to clear all cookies (or "private settings"), your storage goes away.
You could opt to store the XML locally, and store in NSUserDefaults the date when last updated - then on app launch you can check to see if you have a new file.
ASIHTTPRequest makes it pretty easy to say "Save the contents of this URL to a file". So you'd always save the XML to a file, and always read from that file or fetch XML if it was not yet there.
In my experience XML is indeed much slower to parse than plist, even though they're technically the same thing. Fortunately, plist's are pretty easy to deal with and the API's take care of all of the archiving and de-archiving.
Once you have your data in memory, it probably wouldn't be too hard to convert it to the much faster plist representation, check out this doc for more info: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Archiving/Archiving.html
If your app is divided into different pages, you might also consider splitting the file into separate files, and only parsing / de-archiving the information you need when you need it (if you did this on a separate thread and displayed a UIProgressView on the main thread, the delay would probably be barely an issue to the user).
I save some strings and numbers to NSUSerDefault,
but when I uninstall and reinstall the app the data is ereased.
Is there a possibility to store data some where else? Maybe in keychain?
There are two places where you can store data that will persist after an app is deleted, but in both cases, it's not hidden data, so if that's what you're looking for, you're out of luck.
Your two possibilities are 1) Saving data to the photo library. (However, you can't read it back unless you get the user to select the photo for you.) 2) The address book. This is one place where you can create an entry and select it without user input.
You could stash a small amount of data in the comments field of a keychain record.
However, I doubt Apple would allow it because it would violate the principle of sandboxing the apps. It's hard to think of a legitimate reason to have an app leave data behind after it's gone.