NSDictionary and Core Data - ios

Please I am trying to gain some knowledge in core data. I have so far gotten the hang of creating entities and adding, retrieving and deleting values from this entity.
My question is the following. What are the possible ways of storing NSDictionary properties in an entity when using core data?

you should use "Transformable Attributes":
open *.xcdatamodeld file
select entity
add attribute (name it for example "info") and set the type as "Transformable"
generate appropriate NSManagedObject subclass files (File->New->File ... NSManagedObject subclass)
open *.h file and change type for property "info" from id to NSMutableDictionary*
everything else works automatically
for more information see: https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html

There are several ways to approach this:
a. Create an entity that is representative of the NSDictionary, so that each dictionary key is represented by an entity attribute.
b. If you don't like the above approach where you create a separate entity, you can still store the NSDictionary into a single Core Data field of type NSData, provided that you serialize the NSDictionary to NSData first.
//NSDictionary to NSData
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:dictionary forKey:#"Some Key Value"];
[archiver finishEncoding];
// data is now ready to use
You'd also then need to convert the NSData back to NSDictionary when you read it from Core Data.
// NSData to NSDictionary
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
NSDictionary *dictionary = [[unarchiver decodeObjectForKey:#"Some Key Value"] retain];
[unarchiver finishDecoding];
// dictionary is now ready to use
c. Finally, you can use a persistance framework such as Sensible TableView, where all your data structures are automatically fetched, displayed, and saved. Saves me a ton of code myself.

Change the attribute type to Transformable.
If you are using mogenerator (you very well should), the default type generated for a transformable is id.
To have mogenerator generate the specific type NSDictionary, you can add a custom key attributeValueClassName with value NSDictionary for the attribute. Refer to this screenshot.

Related

Is it possible to save an NSMutableArray with NSKeyedArchiver into Core Data?

I have 2 NSMutableArrays in my project and was told that since Core Data doesn't support NSMutableArray that I would have to archive and unarchive it with NSKeyedArchiver to be able to save it to Core Data. I've implemented an NSFetchResultsController for my tableview, how would I go about saving the NSMutableArray in the the NSKeyedArchiver and then using that in Core Data? I'll post some code below of my arrays and the NSKeyArchiver.
- (instancetype)init {
self = [super init];
if (self) {
self.nameList = [NSMutableArray arrayWithObjects:#"1",
#"2",
#"3",
#"4",
#"5",
nil];
self.descArray = [NSMutableArray arrayWithObjects:#"desc1",
#"desc2",
#"desc3",
#"desc4",
#"desc5",
nil];
}
return self;
}
// How arrays are archived
NSData *titleData = [NSKeyedArchiver archivedDataWithRootObject: self.nameList];
.... //Not sure what to do with the archived data
NSData *descData = [NSKeyedArchiver archivedDataWithRootObject: self.descArray];
....
What would I do with the two arrays now that they are archived? How would I be able to add to them later?
My Core Data model is simple it is an entity called "Data" and has 2 attributes of type string called "title" and "desc". The 2 attributes are used to store the arrays.
My hope for this project is to allow the user to add new objects to the tableview, on top of the existing data that make up the cells already, and I want this done in Core Data. I'm aware of NSFetchResultController but am having trouble bringing this all together to get it to work, any help to steer me in the right direction is welcomed
You can save immutable data in core data. U can go with mutable to immutable after that you can by NSKeyedArchiver. Same things with NSUserDefaults.

Insert JSON array into the Core Data entities

I have a JSON returned by REST API to my already existing app that I am trying to fix. I am fairly new to objective C.
[
{
"Activities":"
[
{
"activityid":845,
"activityname":"Registration and networking breakfast",
"actvitydesc":"Registration and networking breakfast",
},
{
"activityid":846,
"activityname":"Plenary session: The Workforce Tsunami",
"actvitydesc":"It's Time to Rethink Talent
}
}
]
There is a core data entity Activity in my app, which contains the following attributes
Activityid activityname activitydesc
How can I insert the JSON data inside my core data entity? Is there any need to create model class to do that? Can I insert my json data directly into core data without creating model objects?
If you already have the entity called Activity you can use the NSManagedObject class to set the value for an Attribute. Try this
NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:#"Activity" inManagedObjectContext:_managedObjectContext];
[managedObject setValue:[NSNumber numberWithInteger:4711] forKey:#"activityid"];
and so on...
You can also create the class by the Classgenerator of CoreData in XCode 8 there are multiple ways. Defaultly the class is generated automatically since XCode 8. If you don't like this you can disable it and generate the class manually. Just go to the CoreData Model --> Editor --> Create NSManagedObject Subclass. Note you have to deactivate the automatic code generation before. If you don't do that, you will become errors while building the project.
If the name of the JSON Attribute is equal to the name of the CoreData Attribute you can also loop over the Dictionary like this:
NSArray *wrapper = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];
for(NSDictionary *dict in wrapper){
NSArray *activities = [dict objectForKey:#"Activities"];
for(NSDictionary *activity in activities){
NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:#"Activity" inManagedObjectContext:_managedObjectContext];
// [managedObject setValue:[NSNumber numberWithInteger:4711] forKey:#"activityid"];
for(NSString *attributeName in activity)
[managedObject setValue:[activity objectForKey:attributeName] forKey:attributeName];
}
}
Hope that helps you...
To insert anything to core data you need to generate models. Create core data model editor (if you don't have one) and add Entities. There is lots of tutorials on the web how to do it.

NSPropertyListSerialization returning nil instead of serialized data

I am putting two NSMutableArray objects into an NSDictionary and trying to serialize, but the method call is returning nil. One array, addresses, is an array of NSString objects. The other, engines is an array of objects that each contain several data types. I am attempting to serialize using the following code:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:engAddr forKey:#"engAddr"];
[dictionary setObject:trainList forKey:#"engines"];
NSData *data = [NSPropertyListSerialization dataFromPropertyList:dictionary
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
Stepping through, the debugger shows the arrays are properly added to the dictionary, but after the line that should serialize the dictionary it shows data = (NSData *) nil.
Where am I going wrong? Thank you for your help!
What kind of objects does engines contain?
Plist supports only specific objects below.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html#//apple_ref/doc/uid/10000048i-CH3-54303
If you want to serialize a custom object, convert it to NSData by NSKeyedArchiver.
To do that, objects must conform NSCoding protocol.

Which is the best way to save data (numbers) in a plist file

Initially I had an object made of three properties (numbers 0 to 12). NSCoder and related issues made me avoid using an object and now I store three NSNumbers directly instead. I save a NSMutableArray with the three values in this way
NSMutableArray *data=[[NSMutableArray alloc] initWithObjects: cardSign, cardNumber, cardColor, nil];
I save and check if data are saved
NSLog(#"wrote %hhd", [data writeToFile:path atomically:YES]);
I try to retrieve the data:
NSArray *dataRead = [[NSArray alloc] initWithContentsOfFile:path];
if (dataRead)
{
cardSign = [dataRead objectAtIndex:0];
cardNumber = [dataRead objectAtIndex:1];
cardColor = [dataRead objectAtIndex:2];
}
Before saving the variable values are correct.
When I try to retrieve the values I get all 0 or (null).
Which is the best way to store three numbers in a plist file and how do I retrieve it?
Most likely your objects "cardSign", "cardNumber", and "cardColor", are not actual objects. When storing array contents or NSArray contents to a file all objects must be Apple recognized objects, NSString, NSNumber, etc...
If for instance cardNumber is defined as follows:
int cardNumber;
Then when "data" is initialized if should be something like (pay only attention to cardNumber)
NSMutableArray *data=[[NSMutableArray alloc] initWithObjects: cardSign, [NSNumber numberWithInt:cardNumber], cardColor, nil];
This line is taken directly from discussion section of the Apple API description of the "initWithContentsOfFile" call.
"The array representation in the file identified by aPath must contain only property list objects (NSString, NSData, NSArray, or NSDictionary objects). The objects contained by this array are immutable, even if the array is mutable.

Get back value of Object key'ed NSMutableDictionary

I have a case where I need to have NSMutableDictionary with NSManagedObject as the key.
Based on this post, I can set NSManagedObject as key in dictionary by:
[NSValue valueWithNonretainedObject:]
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:product forKey:[NSValue valueWithNonretainedObject:category]];
How can I get back the value of dict? I've tried using NSValue again but it crash with no description.
Try using [theValue nonretainedObjectValue]
But if you want to access the keys frequently, a dictionary might not be the right data structure for you. Especially if you want some kind of inverse relationship with objects and keys (if that is what you mean with get back the value of dict).

Resources