Storing complete class object into database in iPhone - iphone

I am new to this development.
I want to store complete object of a class into my database.
Actually I am creating application where user can add multiple views to parent view and want to save it, so that next time when user fetches it, he will get what ever he has saved i.e. views to parent view previously.
Any logic or suggestion on same will really be helpful,
Thanks in advance

Any object you want to save will need to conform to the NSCoder protocol. Keep in mind that if you have custom objects within your parent object that they to will need to conform to NSCoder. Add the following methods to your custom class(es).
- (id)initWithCoder:(NSCoder *)coder {
_inventory = [[coder decodeObjectForKey:#"inventory"] retain];
return self;
}
- (void)encodeWithCoder:(NSCoder *) encoder{
[encoder encodeObject:_inventory forKey:#"inventory"];
}
In the example above I want to encode a player's inventory. If the inventory contains custom objects (as opposed to a bunch of NSStrings for example) they'll also need their own NSCoder methods.
Below I turn it into something you can save out to NSUserDefaults. Adjust appropriately to store in a DB. Keep in mind if you want to send NSData over the wire to store in a DB you'll want to convert it to Base64 and possibly compress it.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData * encodedObject = [NSKeyedArchiver archivedDataWithRootObject:rootObject];
[defaults setObject:encodedObject forKey:kSaveArchiveKey];
[defaults synchronize];
To go the other way, you'll want to grab your NSData, do whatever magic on it as I described above (base64, compression) and unarchive.
PlayerInventory *inventory = [NSKeyedUnarchiver unarchiveObjectWithData:playerInventoryData]

You should choose between NSCoding and Core Data depending on your exact needs. See this post for more info: NSCoding VS Core data

You can store state(value of any attributes) of any object in database. You should use NSCoding.Example here

Related

Deleting files archived with NSCoding

I'm trying to delete all files that my application has persisted using NSCoding. Seems like it should be a simple thing to do, but I can't find an answer, whilst I'm showing just one class here, I have several and I'd like the delete function to save all instances of all classes my app has archived. I'm not doing anything different to NSCoder:
So my interface is defined
Details : NSObject <NSCoding>
My implementation has:
- (id)initWithCoder:(NSCoder *)decoder
{
NSLog(#"initWithCoder 'Details'");
if (self = [super init])
{
NSLog(#"Decoding 'Details'");
self.name = [decoder decodeObjectForKey:#"name"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
NSLog(#"Encoding 'Details'");
[encoder encodeObject:self.name forKey:#"name"];
}
When I write it I'm using:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object];
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:data forKey:identifier];
I did start off trying to look in the documents directory, but I think as I'm writing this and from my research that it will be written to NSUserDefaults (and that might not be the best thing). So at the risk of asking two questions, how do I delete all my objects that are saved/archived using NSCoder to NSUserDefaults (and potentially, should I be setting this to something else (i.e a sub-folder inside the documents folder....if yes, how would I do that).
NSCoding provides a way to transform objects into NSData for easy archiving. What you do with those NSData objects afterward are your responsibility. You may or may not save them to individual files, but NSCoding is not aware of that.
It seems like you have been dumping those NSData into NSUserDefaults using [userDefaults setObject:data forKey:identifier];
You need to delete all entries for every identifier you have used by doing [userDefaults removeObjectForKey:identifier];.
You can't automatically determine what those entries are.
Additionally, you might want to consider not hogging NSUserDefaults and save those to individual files. (look at [NSData writeToFile:]) This will additionally help you track what those files are (you could for example all place them in the same folder/subfolder).

Save Third party Library Custom Object to NSUSerDefault

So,I am using the AFPhotoEditorController and there is property of it named as AFPhotoeditorSession that stores and tracks all user action.THis session class is custom object that inherits from NSObject,I have googled about how to save custom objects in NSUser Defaults and came to know that We can save that class if that class conforms to protocol NSCoding ,I don't know that whether I can change this class,Because it is only.h file that I have in my custom framework of AviarySDk.
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:
[self.sessions objectAtIndex:0]]; // self.session an array of one object of AFPhotoeditorSession
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:myEncodedObject forKey:#"myEncodedObjectKey"];
[defaults synchronize];
NSData *data1 = [defaults objectForKey:#"myEncodedObjectKey"];
AFPhotoEditorSession *obj = (AFPhotoEditorSession *)[NSKeyedUnarchiver unarchiveObjectWithData: data1];
NSLog(#"%#",obj);
I am getting error like :
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AFPhotoEditorSession 0x1c5fa0f0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key modified.'
And you can check the AFPhotoEditor Session class at PhotoEditorSession
You can make the class conform to NSCoding by declaring and defining a category which conforms to that protocol and implements the necessary methods.
Actually creating your own category means that you will have to have it compliant with that object as new ivars are added or changed, forever.
The right way to do this is to determine exactly what you would need to recreate an object of that class - the core values - then create keys and values for each and put them into a dictionary. Put the dictionaries into your user defaults. When you want to retrieve the values, pull out a dictionary, use those values to instantiate the objects.
The other option is to ask the author of AFPhotoeditor to do it, or do it yourself, and send him a pull request. But if you do it as a add on, you will have to update your category everytime the original framework changes.

Problem with savin data!

I have a UitableView and its a checklist. I want to be able to save data when the user leaves the view. Then when the view is opened back up i want there to be the saved data. When i say saved data i mean that the table view is able to add and delete cells also i want to be able to save the checkmarks. Could somebody please provide me with a way or an idea on how to do this?
i know i can save data with:
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
and then save the data to defaults, but i need know how on saving the table view's cells that are add and or deleted! also i would like to know how to save the checkmarks!
Thank you,
Kurt
Sounds like core data would be good here
http://developer.apple.com/library/ios/#documentation/DataManagement/Devpedia-CoreData/coreDataOverview.html
I would suggest using either Core Data, or NSCoding. NSCoding allows you to encode an object as NSData, and reload a replica of that object from NSData.
For instance, saving and loading an array of strings through NSCoding would be something like this:
NSArray * array = [NSArray arrayWithObjects:#"This", #"Is", #"A", #"Test"];
NSData * encoded = [NSKeyedArchiver archivedDataWithRootObject:array];
// save the encoded data to a file...
// load the encoded data from a file...
NSArray * decodedArray = [NSKeyedUnarchiver unarchiveObjectWithData:encoded];
Of course, you will need to implement some NSCoding stuff yourself if you plan on using classes more complicated than NSDictionary, NSArray, NSString, etc.
Documentation for NSKeyedArchiver can be found here. You can also find documentation for the NSCoding protocol here.

How to easily persist application state upon exit

Let's say that my application state is extracted into an object (so that all information specific to app instance is contained in one object) and that object supports nscoding protocol. How can i easily persist it and load it on exit/launch of my application?
My current code looks like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
State* state = (State*)[defaults objectForKey:#"State"];
if(state!=nil)
{
viewController.state = state;
}
}
- (void)applicationWillTerminate:(UIApplication *)application {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.viewController.state forKey:#"State"];
}
But upon loading state is always nil... so I assume it is not the best pattern out there :)
It turns out that NSUserDefaults supports only Property List objects such as NSArray, NSData, etc... no custom objects unless you wrap it in nsdata
There are a number of ways of storing the state of your application before it exits and restoring it when it launches again. The best approach really depends on your application.
If you have a simple object model with a single root object and you tend to need the entire object model in memory at once, then you may find the NSCoding protocol (see link below) a good way of saving state.
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/Reference/Reference.html
Any of the objects you want to persist should implement this protocol's two methods:
- (void)encodeWithCoder:(NSCoder *)aCoder // to serialise the object
- (id)initWithCoder:(NSCoder *)aCoder // to restore an object
Once you've implemented these methods in any of the objects you want to persist, you can serialise your object graph with something like this:
- (void)applicationWillTerminate:(UIApplication *)application {
[NSKeyedArchiver archiveRootObject:yourRootObject toFile:someFilePath];
}
When you want to restore the archived objects:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
id yourRootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:someFilePath];
}
Alternatively, if your application's object model is slightly more complex you might consider using Core Data.
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html
Finally, whilst the user defaults system can be used for storing and retrieving values, it is best used for simple application settings (or preferences). It isn't really intended for saving your entire application's state.
What type of object is state?
I believe that NSUserDefaults will only save NSData, NSString, NSDictionary, NSDate, NSArray and NSNumber.
In the past, I have saved the state into a dictionary and stored it using NSUserDefaults. You could also archive your state and convert it to NSData and save that with NSUserDefaults.

Load data into core-data schema

I am implementing a navigation-based application. The user will drill down to the node of interest. I am using Core Data, mostly because I want to try it out. How do I load the database initially? Should I write custom code that loads the database initially, or is there some tool to do it for me ?
Here's a simple way to preload the Core Data store using plists.
Make a property list containing an array of dictionaries. Make the keys of each dictionary correspond to the keys of your managed object.
Then, call this method the first time the app launches:
- (void)loadDataFromPropertyList {
NSString *path = [[NSBundle mainBundle] pathForResource:#"someFile" ofType:#"plist"];
NSArray *items = [NSArray arrayWithContentsOfFile:path];
NSManagedObjectContext *ctx = self.managedObjectContext;
for (NSDictionary *dict in items) {
NSManagedObject *m = [NSEntityDescription insertNewObjectForEntityForName:#"TheNameOfYourEntity" inManagedObjectContext:ctx];
[m setValuesForKeysWithDictionary:dict];
}
NSError *err = nil;
[ctx save:&err];
if (err != nil) {
NSLog(#"error saving managed object context: %#", err);
}
}
Call loadDataFromPropertyList the first time the app launches by including the following code in the implementation of application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"])
{
[defaults setObject:[NSDate date] forKey:#"firstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self loadDataFromPropertyList];
}
There is no automatic (i.e. built-in) method for importing data into a Core Data context.
I suspect that this is because Core Data is really an object graph management framework (that just happens to be able to persist that object graph to disk) and the mapping between data and object instances depends on the schema (and so will require at least some code).
If you already have the data in another format, you should read the section of the Core Data Programming Guide on importing data into a Core Data context. If you don't already have the data in an other format, you will have to write code either way (to generate an intermediate format or to populate the context directly).
Finally, although it is not really a public API, the Core Data XML format is pretty easy to work with by hand or using any number of XML-based tools. Depending on the complexity of your data, you may be able to reverse-engineer the XML schema enough to generate an XML-backed persistent store. You could then migrate this store to an SQLite persistent store and you're on your way.
Currently as far as I know you have to write custom code to populate the database.
This does seem like a downside, I'd really like to see a tool for batch (shell) pre-population of data sources meant to be used by CoreData.