I have to ship a simple app with a very tight deadline so I have no time to learn anything othen than what I know (meaning learning Core Data for example). Would it fine to use NSUserDefaults to store data for my app? It's almost like a check list app where users have list of items with some data accompanying each item.
Other than that I would be using a service like Parse which I can handle thanks to having built my last app with it.
Would Apple reject an app if you use NSUserDefaults for something other than settings/preferences?
Thanks!
From Apple's documentation:
The NSUserDefaults class provides a programmatic interface for interacting with the defaults system. The defaults system allows an application to customize its behavior to match a user’s preferences. For example, you can allow users to determine what units of measurement your application displays or how often documents are automatically saved. Applications record such preferences by assigning values to a set of parameters in a user’s defaults database. The parameters are referred to as defaults since they’re commonly used to determine an application’s default state at startup or the way it acts by default.
[...]
Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for "MyStringDefault", the string you later retrieve using stringForKey: will be immutable.
In other words, this is not the place to store mutable application data.
If the checklist data is going to be modified by end users (i.e. adding new items, or editing the text of the items on the checklist) it really would be worthwhile to learn how to use Core Data. Over the years it really has become very easy to learn and use.
You can find a great series of Core Data tutorials at http://code.tutsplus.com/series/core-data-from-scratch--cms-653
If you're looking for something that's been updated for iOS 8 and Swift (although they're mainly syntax changes for the new language), you can check out http://www.raywenderlich.com/85578/first-core-data-app-using-swift.
Apple wouldn't reject even if you unnecessarily burden NSUserDefault. But users of your App will definitely uninstall it or OS will kill it if app crashes or hangs their iPhone.
NSUserDefault : is a fast way to access the data. it stores in (key,value) pair and lives as long as your app is installed in phone. Usually session based small amount of data is supposed to be stored in it. Not ur entire database.
Database (CoreData or Sqlite) : Behind the seen Coredata is also a sqlite with objects talking to each other(Think in terms of model instead of tables if using Coredata).
I simple suggest you use Coredata if your data by any chance is big or expected to get big. CoreData wont take much time.
Yes, you can store data in NSUserDefaults, which will be the quick and dirty method to store data locally.
You could use Core Data, though I prefer to just use FMDB and write my own SQLite statements. You could also use NSFileManager and just read and write everything to a JSON file. Parse will probably be overkill if all you are doing is storing a list of check list objects.
Go for NSUserDefault fro now !
When the App is submitted fro approval, look at SQlLite. this will be useful for the next projects.
Parse... sure but make sure it's not overkilling especially if you have limited amount of data
Good Luck !
Related
This question is not about the technical problem, but rather the approach.
I know two more or less common approaches to store the data received from the server in your app:
1) Using managers, data holders etc to store the data. They are most often some kind of singleton and are used to store the models received from the server. (E.g. - the array of the posts/places/users) Singletons are needed to be able to access the data from any screen. I think the majority of apps uses this approach.
2) Using Core Data (or maybe Realm) as in-memory storage. This approach avoids having singletons, but, I guess, it is a bit more complex (and crash risky) to maintain and support.
How do you store data and why?
P.S. Any answers would help. But big "thank you" for detailed ones, with reasons.
The reason people opt to use Core Data/Relam/Shark or any other iOS ORM is mainly for the purpose of persisting data between runs of the app.
Currently there are two ways of doing this, for single values and very small (not that I encourage it) objects you can use the UserDefaults to persist between app launches. For a approach closer to a database, infact in the case of Core Data and SharkORM, they are built on top of SQLite, you need to use an ORM.
Using a manager to store an array of a data models will only persist said models for the lifetime of the app. For example when the user force quits the app, restarts their device or in some circumstances when iOS terminates your app, all that data will be lost permanently. This is because it is stored in RAM which is volatile memory, rather than in a database on the disk itself.
Using a database layer even if you don't specifically require persistence between launches can have its advantages though; for instance SharkORM allows you to execute raw SQL queries on your objects if you don't want to use the built in powerful query builder. This can be useful to quickly pull the model you are interested in rather than iterating through a local array.
In reply to your question, how do I store data?
Well, I use a combination of all three. Say for instance I called to an API for some data which I wanted to display there and then to the user, I would use a manager instance with an array to hold the data model.
But on the flipside if I wanted to store that data for later or if I needed to execute a complex query on it, I would store it on disk using Shark.
If however I just wanted to store whether or not the user had seen my on boarding flow I would just persist a boolean value into UserDefaults.
I hope this is detailed enough for you.
CoreData isn't strictly "in-memory". You can load objects into your data model and save them into their context, then they might actually be on disk and out of main memory, and they can easily be brought back via fetch requests.
Singletons, on the other hand, do typically stay in main memory all the time until the user terminates the app. If you have larger objects that you are storing in some data structure (e.g. full resolution images when all you really needed was a thumbnail), this can be quite a resource hog.
Given the recent addition of local datastore for iOS to Parse, it should be possible to rely exclusively on Parse to manage app's database, thus totally avoiding Core Data. Does this sound like a good idea? What would be the pros and cons of such an approach?
In particular, I am wondering whether it will be possible to pre-populate Parse local datastore with some data, and include this database as a part of the app when submitting to appstore.
UPDATE
From the comments that were posted, it seems that people misunderstood my intended use case. Sorry guys, I should have made my question more clear from the beginning. Let me clarify it now, anyway.
So, there is some amount of data in Parse database on the web, same for every user, e.g. a catalogue of books. It will be updated every now and then. What I want is to publish an app on App Store which is pre-populated with Parse data store, as it stands at the moment when the app is published. For that to happen, I'd like to pin all available data when building my app and ship that data store along with the app. The problem is that the pinned data will be stored on device's (or emulator's) file system, it won't be part of the project. That's why if I build the app and submit it to app store, the data won'd be included.
Any suggestions how to attach the local data store to the app?
The local data store is stored in the sandboxed part of the filesystem in iOS. When you package the store with the app, it'll live in the signed application folder, not in the location Parse expects it to be.
So, if you were looking to do this, you'd need to include your default local data store in the application on building/submission, and copy it into the location Parse expects it to be in (which is Library/Private Documents/Parse and the file is called ParseOfflineStore) when your application starts up. This must happen before you call enableLocalDatastore, or an empty one will be initialized.
It should be possible!
Read this in the docs. Parse has a highly resourceful and fully documented guide for their backend.
https://parse.com/docs/ios_guide#localdatastore
Per my comment above concerning didFinishLaunchingWithOptions; it has been a place for your to create objects on launch, I have been doing that for a long time. Especially with channels. However, by enabling the local data store you can access those objects you pinned or created with a simple query with no reachability per your concern. Either way they both are created on disk. Core Data has a lot more cons. Especially with NSFetchedResultsController and the flexibility it offers. It's all up to you what you want to do with your app. PFQueryTableViewController isn't bad but if your direction and vision for your app is to be exclusively Parse then why not. It's a great feature. However I didn't see anything in the docs about the local queries effecting your limit so I would suggest looking into that if you have a large audience performing numerous queries per second.
Take advantage of their docs. They do a great job at keeping us informed.
Design question:
My app talks to a server. Json data being sent/received.
Data on server is always changing, and I want users to see most current data, not stored/cached data. So I require a user to be logged in order to use the app, and care not to persist data in the app.
Should I still use CoreData and map it to Json's.?
Or can I just create custom model classes and map Json's to it's properties, and have nsarray properties, which point to its child objects, etc. ?
Which is better?
Thanks
If you dont want to persist data, I personally think core data would be overkill for this application
Core Data is really for local persistance. If the data was not changing so often and you didnt want them to have to get an updated data everytime the user visited the page, then you would load the JSON and store it locally using CoreData.
Use plain old objective-c objects for now. It's not hard to switch to Core Data in future, but once you've done so it gets a lot harder to change your schema.
That depends on what your needs are.
If you need the app to work offline, you need to store your information somehow in the client.
In order to save on network usage, you could store locally, then query the server to see if it had an updated answer -- you could do this by sending a time stamp to the server and return a 304 Not Modified if the entity hasn't changed.
Generally, it depends on how much time you have to put into the app and what your specific requirements are, but as a general rule I would optimise for as low bandwidth usage as possible, as that not only reduces potential data costs, but also means the answers will be more quickly available to your users (when online and they have not changed) and also available offline.
If you do not wish to store data locally at all,
I am new to iOS development and Mobile app development in general, I have decent knowledge about Objective C and MVC patterns to be used and I have never done any Mac development.
I am struggling to understand what NSUserDefaults is for?
We already have something like PList which stores data as XML and we have SQLite which is lightweight DB for such devices.
Then why do we have it?
Is it an alternative simple key-value storage for our app in the same way we have different types of storage on the cloud like an RDBMS and a key-value based NoSQL store etc ?
For NSUserDefaults, Apple docs say that :-
"Applications record such preferences by assigning values to a set of parameters in a user’s defaults database"
What do they mean by user's default database?
My guess is that, like in any multi-user operating system we have various user accounts and in the same way in Mac as well we might be having multiple users each having a database from where applications would load saved preferences for that user.
So like Mac OS X, does iOS also have multiple users and depending upon whichever is logged in NSUserDefaults picks his/her preferences?
Please tell me if I am wrong.
One thing that hasn't been mentioned yet: NSUserDefaults supports all basic scalar (float, int, BOOL) types, as well as the plist-compatible types: NSData, NSString, NSNumber, NSDate, NSArray, and NSDictionary. (You mentioned plists as an alternative--NSUserDefaults is just a front-end to a standard plist file in the application's Preferences folder.) This makes it easy to create persistent storage for your application state in just a few lines of code. Even better, if you implement NSCoding on your model objects, you can archive them into an NSData and put them in NSUserDefaults:
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:arrayOfModelObjects];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:kDefaultsKeyModelObjects];
and restoring your app data is as simple as
- (void)viewDidLoad
{
NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:kDefaultsKeyModelObjects];
arrayOfModelObjects = [[NSKeyedUnarchiver unarchiveRootObject:data] retain];
// error checking, tell UI to load the new values, etc...
}
(kDefaultsKeyModelObjects is a string constant you've defined somewhere. Always put your NSUserDefaults keys in one place! Having a typo in a key name can take hours to debug. :)
If you used, e.g., SQLite to store your application data, you have to write a lot of code to move your model data in and out of the database. That makes sense if you're dealing with a lot of data, need efficient searching, etc.; but if it's, say, a list of servers in a networking app, it's easier and cleaner to throw them in NSUserDefaults.
One last thing: NSUserDefaults is great for prototyping. Even if you know you're going to need a SQLite store eventually, you can start out using NSUserDefaults as a quick-and-easy persistent store, and get your UI working and your data model fleshed out before writing a bunch of database code.
So like Mac OS X, does iOS also have multiple users and depending upon
whichever is logged in NSUserDefaults picks his/her preferences ?
Nope, on iOS the defaults plist is in the application's Library/Preferences folder, not in a user-specific folder like it is on OS X. I can't imagine iOS will ever have multiple logins, but you never know. If it did, they'd have to make separate defaults plists for different users.
NSUserDefaults are used to save small portions of data the App is dependent on to run correctly, while other approaches are good to store bigger amounts of data, that the app work with.
NSUserDefaults makes is incredible easy, as you don't have to worry about files, entities, fetches,…. It is all done in one line.
It's originally for storing settings, but does seem to get (ab)used for a lot of other things if the questions on SO are anything to go by. The "point" of it is that it provides a single-line data persistence and retrieval method for a wide range of data types.
There is no multi-user configuration (yet?) on iOS (have you ever had to sign in to your iPhone?) that is built in to NSUserDefaults, but because OS X and iOS are built on the same foundation, the same class is used for both operating systems.
iOS is a single-user OS. Hence, NSUserDefaults is used differently in OSX and iOS.
In iOS, you normally use NSUserDefaults to save application preferences and/or user data on the "iOS defaults system". Data saved in the defaults system will be persistent at all time even when you reboot the iOS device. As a matter of fact, even when the user updates the application.
You typically want to use NSUserDefaults to save application preferences/settings. Any other massive data such as game data or realtime calculations should be save in CoreData or sqllite in the documents directory.
NSUserDefaults stored values for only your application.
Note - It is not meant to serve as a replacement for a traditional store for data (Core Data, SQLite, Property Lists, etc are meant for storing application data). What NSUserDefaults is meant for is for specific key value pairs.
For example, I use it to store an authenticated user's networkid and full name once the login process is done. Upon session timeout or logout, I clear those values. For this NSUserDefaults shines.
I am trying to find the best option for caching multiple string values with the ios system.
The two I have found so far are NSCache and NSDictionary however from what I have read NSCache will dump data if you start to have trouble with your memory and well quite frankly I dont fully understand NSDictionary.
So I am wondering what if any other options there are out there that will suite what I am trying to achive.. for instance maybe using core data / local sqlite etc? basically the plan is to get information from a online database, store some of the more important information on the phone that is only ever updated when the version number (and int) on the database has changed, the I will flush my cache and update it with the new information.
If I understand you correctly, it seems as though every time you have a new version on your server, you want to download the new data, and store some of it to the device.
If that's the case, you can write all the data to a file, and save it on the phone, and then reload the data that you need from that file later. I personally like using NSCoding for this, as it let's you store data easily to a file, and then read it back later when you need it. You don't even need to read all of the data at once, just what you need at what time, which can help with memory issues. You can also make your own custom objects NSCoding compliant, and it becomes even easier to store data!
I would suggest trying NSCoding out. There are also tons of tutorials out there to help you figure it out.
Also, NSDictionaries are super easy to use. You give it an object and a key to store it with, and when you want the object back, simply give the NSDictionary the key, and you'll get the object back.
Hope that Helps!