Saving data to storage - iphone

Suppose I have some data I want to post to a server. You're in a deep, deep underground cellar (or you use t-mobile) and you have no internet connection. Where does that data go? Just leave it there and wait for a connection? I would rather save that data, and make it available for upload the second you have a connection.
Would using SQlite be the best way of doing this? It's just a couple of objects i want to temporarily store.

If it's only a couple of objects either save the data in NSUserDefaults or in a plist file.
NSUserDefaults set:
[[NSUserDefaults standardUserDefaults] setObject:savedStr forKey:objectDataStoreName];
[[NSUserDefaults standardUserDefaults] synchronize];
NSUserDefaults get:
savedStr = [[NSUserDefaults standardUserDefaults] objectForKey:objectDataStoreName];
or use a plist:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *newDirectory = [NSString stringWithFormat:#"%#/savedData", [paths objectAtIndex:0]];
[[NSFileManager defaultManager] createDirectoryAtPath:newDirectory withIntermediateDirectories:YES attributes:nil error:nil];
NSString *fullFileName = [NSString stringWithFormat:#"%#/savedItemsFile", newDirectory];
savedItems = [[NSMutableArray alloc] initWithContentsOfFile:fullFileName];
if (!savedItems) {
savedItems = [[NSMutableArray alloc] init];
}
savedItem = [[NSMutableDictionary alloc] init];
[savedItem setObject:savedStr forKey:objectDataStoreName];
[savedItems addObject:savedItem];
[savedItems writeToFile:fullFileName atomically:NO];

Well that is up to you, apple specifies you need to check if there is an internet connection available. And you will receive error's if you request fails.
If you can send the data later just save it and retry later. If you can't send the data on a later date then inform the user that the data could not be send.
It all depends on the specifications of the app.
I've uses plist, SQLite and coredata to keep data on the device and send them to the server when a network connection becomes available.
If you all ready store the data in database just add a bit which tells you if you have send the data to a server, or beter yet get the server to return you an identifier for the upload so you may update some record later on.

If it is not something big you can use NSUserDefaults
If it is something big I recommend you to use Core Data

Related

new file is created instead of copying file

EDIT: Doesn't look like it's working with the simulator either now.
Some more info, It seems if I install an archived version that did work, then install the one that wont work, right over it, everything works great. but when I delete the archived version, and install the new one, thats when everything stops working.
I was just testing my app on my iPhone, and it was working perfectly, and when I archived it, and installed the ipa on my phone, the database stopped working. no errors occur when you load the database, and like I said before, it was JUST working. I didn't change ANY code. it still works on the simulator, so I know it has to do with the copying of the database. here's the relevant code:
dbPath=[NSString stringWithFormat:#"%#/Documents/database.sql", NSHomeDirectory()];
// Get the documents directory
NSFileManager *fmngr = [[NSFileManager alloc] init];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"database.sql" ofType:nil];
NSError *error;
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"didLaunchFirstTime"])
{
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"didLaunchFirstTime"];
[fmngr removeItemAtPath:[NSString stringWithFormat:#"%#/Documents/database.sql", NSHomeDirectory()] error:&error];
if(![fmngr copyItemAtPath:filePath toPath:[NSString stringWithFormat:#"%#/Documents/database.sql", NSHomeDirectory()] error:&error])
{
// handle the error
NSLog(#"Error creating the database: %#", [error description]);
}
}
My query looks like this, because I'm using FMDB to query the database. It's in a separate method called when the user presses the search button.
FMResultSet *s = [db executeQueryWithFormat:#"SELECT Gurmukhi, ShabadID, FirstLetterStr FROM Shabad WHERE FirstLetterStr LIKE %#", searchString];
I also unzipped the ipa to check if the database wasn't blank, and it isn't. I have no idea what's going on.
You should not be hardcoding directory paths in your app - Apple provides functions to get them:
When you want to find the file in your bundle, you get it this way:
NSString *dbPathOld = [[NSBundle mainBundle] pathForResource:#"database" ofType:#"sql"];
Now you have a path to the sql file you provided with your app.
When you want to copy it, you use this code:
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *dbPathNew = [docDir stringByAppendingPathComponent:#"database.sql"];
Other comments:
1) Why not use the NSFileManager *fm = [NSFileManager defaultManager];?
2) With your standard defaults, you are registering them in an initialize method in your app delegate? You are synchronizing them after you update values (so in fact "didLaunchFirstTime" is set the second time)? You might want to add a log message so you can know for sure.

iOS - plist file, nsuserdefaults or text data file

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.

How to cache or store parsed xml file?

My app parses an xml file from my server, but I want to store parsed xml file and next start of my app, controller initially should load stored xml file, then controller should parse it again to check that there may be an update I did on xml file, if there is, new elements parsed should also be stored again.
I am referring to those app such as magazines, newspaper apps. When you open those kind of apps, it loads stored data that was downloaded previous session. Yet, after it loads, it starts to update the data, and it stores new update again.
Where do I start? What do you guys suggest?
Thanks in advance...
You can use CoreData or SQLite (use Objective-C wrapper FMDB https://github.com/ccgus/fmdb) to persist your XML. Then update the database everytime you see a unique id. Depends on how your XML data is.
It's actually quite easy to store to the documents directory. For example:
NSData *data; //this is your xml file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docs = [paths objectAtIndex:0];
NSString *filename = [NSString stringWithFormat:#"test.xml"];
NSString *path = [docs stringByAppendingPathComponent:filename];
[data writeToFile:path atomically:YES];
Then to retrieve it later, you can get the path like above, but retrieve the file instead of writing it:
NSData *data = [NSData dataWithContentsOfFile:path];
either CoreData or SQLite can do the trick

Write/Read from property list on iPhone

I know there are thousands of tutorials on the topic however I don't get it to work.
What I am trying to do is to read an value from a plist file. Then I check whether or not I have to update the value. This part is ok. However I don't managed to get the value saved in plist file. I have a Settings.Bundle and it is where I am trying to read/store.
It is just a simple string.
Thanks in advance
The following will give you a NSDictionary with your settings bundle information.
[[NSBundle mainBundle] infoDictionary]
If there are any other generic plist you would like to read you can easily load them into a NSDictionary using
[NSDictionary dictionaryWithContentsOfFile:filePath];
//or
[[NSDictionary alloc] initWithContentsOfFile:filePath]
Also I would like to add for reading and saving values I would recommend doing that in the NSUserDefaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
id anObj = [userDefaults objectForKey:#"myKey"];
//Modify anObj
...
[userDefaults setObject:anObj forKey:#"myKey"];
[userDefaults synchronize];//Save immediately if you choose
You cannot modify files/folders present in your app bundle (such as Settings.bundle.) They are read-only.

Saving application data state on exit

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:]