I am working on a mobile app which needs a lot of data. Simply put, the data will be for multiple languages and consist of all the words possible for that language. The app would start with only the English language and a lot of it's words. Then the user can choose to download more languages and their data.
I am trying to figure out the best way to read/save/update this data. Should I create a plist file with English data to start with and just keep adding more data as user downloads new languages? Or should I save all the data in nsuserdefaults? Or, should I just include a text file with all the data and parse it on the fly?
Suggestions?
ps: i understand that as this is a mobile app, file space and parsing time have to be considered
Please read my answer here: https://stackoverflow.com/a/7215501/832065
As said in that answer, all NSUserDefaults are stored together in one plist.
A plist and NSUserDefaults are basically the same, however NSUserDefaults should ONLY be used for saving preferences and not a big amount of data. So don't use NSUserDefaults!
I would consider saving this in a plist (NSDictionary). Like this you can have all data sorted in that file. Simply set the "words" (NSString I assume) as object, and the language as key.
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
[dict setObject:words forKey:language];
[dict writeToFile:filePath atomically:YES];
same for reading:
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSString *words = [dict objectForKey:language];
EDIT:
If each word is assigned to a number (you can just use NSArray) it doesn't differ much:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
NSArray *words = [NSArray arrayWithObjects:allTheWords,nil];
[dict setObject:words forKey:language];
[dict writeToFile:filePath atomically:YES];
same for reading:
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSArray *words = [dict objectForKey:language];
NSString *word = [words objectAtIndex:numberAssignedToWord];
I hope this helps! :)
I would recommend using either an SQL database directly or Core Data. If you have a lot of data, you don't want to load that data completely into memory all the time. It is also easier to handle updates, changes or additions of data.
But your question is so general, and doesn't tell anything on what you actually want to do with the data, how large the data is in KByte or MByte, it is hard to give any good answer.
Writing a lot of data into a text file, user defaults, plist or something similar, doesn't seem the right choice. Using Core Data would be the default way to do such things on iOS.
I thing the easiest way would be to handle the data in a NSMutableArray and store it within the application using NSUserDefaults.
You can handle your data within a NSMutableArray, like so:
NSMutableArray *yourDataStuff = [[NSMutableArray alloc] init];
[yourDataStuff addObject:#"Your data 1"];
[yourDataStuff addObject:#"Your data 2"];
[yourDataStuff addObject:#"Your data 3, etc.."];
Then you can store it using NSUserDefaults, like so:
[[NSUserDefaults standardUserDefaults] setObject:yourDataStuff forKey:#"myData"];
And read your data, like so:
yourDataStuff = [[NSUserDefaults standardUserDefaults] objectForKey:#"myData"];
I think you cannot save large data in the NSUserDefault , and you maybe can not do IO with plist , i had done this , when you read or save , you must read in the whole .plist , and you may reveive memory warning , or crash. you can use C (fread,fwrite) write the data in a .txt , and you may read and write with data stream.
Related
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
separating keys and objects from NSMutable dictionary and use the values in insert command of sqlite
I have an NSDictionary containing parsed JSON data. How can I push these data to a database so that I can extract them from database for further use?
I am using SBJSON for parsing.
If your design requirements specify sqlite, then I would recommend using Gus Mueller's FMDB so that you do not have to work directly with raw sqlite.
NSString $title = [jsonDictionary objectForKey:#"title"];
// other keys, values, etc...
NSString $query = [NSString stringWithFormat:#"INSERT INTO myTable t (t.some_column) VALUES ('%#'),$title];
FMResultSet *results = [_db executeQuery:$query];
That said, as Chris said above, Core Data is often a better solution than sqlite. Brent Simmons (NetNewsWire developer) has a series of posts about this subject, like this one.
The exception to the "Core Data is better than sqlite" mantra for me is the situation where you want to provide initial data but do not want to perform an initial import into Core Data.
Use core data for this matter. Here is a good tutorial to start with:
http://mobile.tutsplus.com/tutorials/iphone/iphone-core-data/
Following code goes to create the dynamic plist file and that file stores into the bundle and that data can be access and the insert the data into the .plist file.
NSString *strPathToAudioCache=[NSString stringWithFormat:#"%#/%#",
[(NSArray*)NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0],
#"data.plist"];
NSMutableDictionary *dOfAudios=[NSMutableDictionary dictionaryWithContentsOfFile:strPathToAudioCache];
NSLog([dOfAudios allKeys].count>0?#"Value is exist":#"Value is not exist");
if([dOfAudios allKeys].count>0) {
[dOfAudios setValue:#"Key_for_value" forKey:#"value_for_key"];
} else {
dOfAudios=[NSMutableDictionary dictionary];
[dOfAudios setValue:#"Key_for_value" forKey:#"value_for_key"];
}
[dOfAudios writeToFile:strPathToAudioCache atomically:YES];
Thanks in advance. I create an array with 6 parts, each an NSString in one of my views. Each string is taken from a UITextField. I want to make a save button that saves the Array into a plist. I then want a TableView to display a table sorted by the first object in the array, the first string.
I've created a blank plist with the name I want and named the plist the same thing as the array. Frankly, I'm lost after that. I don't understand if what I'm making is a dictionary in the plist or an array, and how to do it.
Once the table is made, I think I can handle pushing new views from the selected row.
Anything would help. Thanks and stack overflow has been really helpful.
Thanks again.
If you are really set on using files, to this to write an array to your .plist:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:theArray forKey:yourKey];
[dictionary writeToFile:#"/somepath/blah.plist" atomically:YES];
[dictionary release];
This will set the root of your .plist file to be a NSDictionary.
If you want it to be an NSMutableArray just change the class of the *dictionary.
Answer via: primary source
To store data it's better to use NSUserDefaults and not files because reading and writing it it's much easier.
There is a primer at: Primer link
I know that NSUserDefaults can read the key and value from plist file.
Is it possible to read the structure of a key?
For example:
Key 'Count' is an integer and has option
1,2,3,4,5
the codes below can get the value 'Count'
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"Count"]!=nil)
{
NSString *s=[[NSString alloc] initWithString: [defaults objectForKey:#"Count"]];
NSInteger v=[s intValue];
[s release];
}
But I prefer to get all options and store to a NSArray or a better storage structure.
Is it Possible?
I read bundle settings the following way:
// Get path to Root.plist file in settings bundle and retrieving its contents
NSString* tPath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"bundle"];
settingsBundle = [[NSBundle bundleWithPath:tPath] retain];
NSDictionary* tSetDict = [NSDictionary dictionaryWithContentsOfFile:[tPath stringByAppendingPathComponent:#"Root.plist"]];
// Get array of preference dictionaries
NSArray* prefs = [tSetDict objectForKey:#"PreferenceSpecifiers"];
// Iterate through dictionaries to find required value
for (NSDictionary* setDict in prefs){
NSString* type = [setDict objectForKey:#"Type"];
if (![type isEqualToString:#"PSMultiValueSpecifier"]){
// Get possible preference values for PSMultiValueSpecifier case
// You may need to know value type in advance - not sure about that
NSArray* values = [setDict objectForKey:#"Values"];
}
}
I'm not exactly sure I understand your question but you can't directly access the user defaults system save through its defined methods. You can't read them out in one big chunk.
The defaults system isn't actually a means of reading plist files, its an more of an API for accessing a database maintained by the OS itself. Although, you don't see it much on the iPhone, its actually a very large and complex system for managing preferences not only for individual apps but also for users, groups of users, computers and networks. It seems trivial on iOS because you don't have the flexibility of configuration and use that you have on MacOS proper.
It would be impossible to read out the entire defaults because they are huge and much larger than you would expect even on iOS.
Instead of jumping through the hoops in the code you showed in the answer, you should access the data in the key using one of the dedicated methods for the type of data stored. In this case:
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSInteger v=[defaults integerForKey:#"Count"];
Even if you did read the defaults out in one chunk, you would just find yourself using the same type of calls and code to access the data in the alternate data structure as you would in using the defaults in the first place. You might as well use the defaults system.
I want to store the content of some variables in a file. The user nor the application should change the value. It would be great if the user cannot read the content of this file. On startup the application reads the file and initialize some (global?) variables with the content.
The file should contain some values like server URL and so on. This could change, but I only want to manage a preference file rather than updating the source code. On an update for example only the preference file will get exchanged.
How can I manage that?
NSUserDefaults is not intended for such issues I think. Should I use a a plist or a normal txt file?
How would the access to the content of the file look like?
Cheers
Sounds to me like NSUserDefaults is exactly what you need. It will let you store URLs (as strings) and other basic types of variables.
Why do you think NSUserDefaults is not the right solution here?
Give it a try! It's easy to use and reliable.
Use a plist. You can load it with -[NSDictionary initWithContentsOfFile:] (you can save a dictionary to a plist just as easily with -[NSDictionary writeToFile:atomically:], though it doesn't sound like you need to do that).
So the solution I'll use is that I load a plist file as default value for my NSUserDefaults:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"plist"];
NSDictionary *settingsDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
[[NSUserDefaults standardUserDefaults] registerDefaults:settingsDict];
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSString *serverURL = [settings stringForKey:#"ServerURL"];
NSLog(#"%#", serverURL);
Taken from iPhone App : Where do I put a config file?
So I'll use both plists and NSUserDefaults. settings I'll define as global variable in the main.m. One problem remains:
How to differentiate between user defaults and system defaults?
I have an NSMutableArray with 24 strings.
I need to save this data if a user gets a call or quits the application.
I have been looking into many examples but for some reason can’t seem to determine the best way to save the data.
The 24 strings correspond to 24 buttons and their state. When a button is clicked, it displays the corresponding Array info for that buttons tag (0 – 23). What I would need to retain is if 10 buttons where clicked and their data shown, how/what would be the best way of retaining this data so it can be reloaded when the app starts?
I am thinking I would need to store:
Button Tag,
Buttons corresponding Array value,
Button state (whether it has clicked and value is show or not)
I would store this data on exit of the application and then when app is started again, I would determine if this stored data exists, if so populate the array and examine the button states to determine if it had already been shown and if so, set it accordingly. Then when this file was loaded, I would delete the stored data (.DAT file if stored this way). This way if a user quits gracefully, on next start up, it would start a new game.
I have looked at several examples where they store data into a .DAT file but am having problem implementing this….and wondering if this is even the best way.
Any help or thoughts on this is greatly appreciated.
Geo…
you should be able to store it in NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:buttonState forKey:#"buttonState"];
[defaults synchronize];
// Then to get the state back
NSMutableArray* buttonState = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"buttonState"] mutableCopy];
You could save the data to a plist in the Documents directory. If the data is there, load it up, and if not, it would suggest a clean run.
To load the data:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents = [paths objectAtIndex:0];
NSString *filePath = [documents stringByAppendingPathComponent:#"buttonState.plist"];
NSMutableDictionary *buttonState = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
To save the data:
[buttonState writeToFile:filePath atomically: YES];
I save my data by using NSKeyedArchiver/NSKeyedUnarchiver, since your NSMutableArray already supports the NSCoding protocol, you can just use
yourArray = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
[NSKeyedArchiver archiveRootObject:yourArray toFile:file];
Edit:
I suppose NSArray's own methods work also
[NSArray writeToFile:]
[NSArray initWithContentsOfFile:]