Insert JSON array into the Core Data entities - ios

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.

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.

Get all entities from Model.xcdatamodeld

In my project I am using MagicalRecord framework (implementation of active record pattern for Core Data on iOS). How can I retrieve all existing ENTITIES from my .xcdatamodeld file? I have to iterate though all entities (classes that inherit from managed object in my project) to truncate stored data.
I have only default configuration set in my model file. So for the following data model:
My code that show how it should look like:
NSArray *myEntities = // Retrive my entities.
foreach (Class *c in myEntities) {
[c MR_truncateAll];
}
Okey I have found the solution over here. The answer is pretty simple:
NSArray *allEntities = [[NSManagedObjectModel MR_defaultManagedObjectModel] entities];
for (NSManagedObject *mo in allEntities) {
[[mo class] MR_truncateAll];
}

iOS: core data to many relationship

I have a doubt how to manage a "to many relationship" in core data.
In my example I have the main identity 'Struct' that have a "to many relationship" with another identity called 'Id_loc'
Then, I have this object in a JSON file that is a Struct identity:
{"id":"s1",
"n":"Name Struct",
"id_loc":["l1","l2"]} //id_loc can contain many element
when I parse this object I have id_loc as an array.
Inside Struct class I have two methods:
- (void)addLocObject:(Id_loc *)value;
- (void)addLoc:(NSSet *)values;
then I do this to store id_loc array inside:
Struct *struct = [NSEntityDescription insertNewObjectForEntityForName:#"Struct" inManagedObjectContext:context];
NSArray *array_loc = [element objectForKey:#"id_loc"];
NSSet *set = [NSSet setWithArray:array_loc];
[struct addLoc:set];
Is it a right way?
Is it not necessary to call this?
Id_loc *loc = [NSEntityDescription insertNewObjectForEntityForName:#"Id_loc" inManagedObjectContext:context];
EDIT
Is it the right answer?
Struct *struct = [NSEntityDescription insertNewObjectForEntityForName:#"Struct" inManagedObjectContext:context];
NSArray *array_loc = [element objectForKey:#"id_loc"];
for (id loc in array_loc){
Id_loc *loc = [NSEntityDescription insertNewObjectForEntityForName:#"Id_loc" inManagedObjectContext:context];
loc.ident = loc;
[struct addLocObject:loc];
}
You cannot really save an NSSet into the CoreData just like that. NSSet contains other CoreData entities only which are related to your main object.
To save an array with data you need to use NSData property and use NSKeyedArchiver to archive your NSArray with NSStrings.
However even it's simplest solution there are some limitations. For example you won't be able to use and predicates on those properties. Therefore I would recommend to make another entity which is "Location" and create a location objects based on those "l1", "l2" values.
Yes you use addLocObject: or if you want to add multiple ones you use - (void)addLoc:(NSSet *)values; But you have to create those objects - create them in core data withing your context and than add it to main object.
Probably if you have ID you want also to select first existing locations and create them only if the don't exist.

One to many relationship: not able to save

I am trying to create a one to many relationship with some data I have.
I have a single Project and many items, I am trying to set up the controller to save them but this is the first time I have ever used a one to many relationship and my head is about to explode.
This is what my save method looks like
- (void)writeProj:(NSArray *)recivedProData ItemsData:(NSArray *)itemsData {
// WRITE TO CORE DATA
NSManagedObjectContext *context = [self managedObjectContext];
for (NSDictionary *dict in recivedProData) {
Project *project = [NSEntityDescription insertNewObjectForEntityForName:#"Project" inManagedObjectContext:self.managedObjectContext];
project.projectNumber = [dict valueForKey:#"ProjectNumber"];
project.projectDescription = [dict valueForKey:#"Description"];
// project.items = [dict valueForKey:#""]; // this is the relationship for project
}
for (NSDictionary *dict in itemsData) {
Items *items = [NSEntityDescription insertNewObjectForEntityForName:#"Items" inManagedObjectContext:self.managedObjectContext];
items.description = [dict valueForKey:#"Description"];
items.area = [dict valueForKey:#"Area"];
items.stage = [dict valueForKey:#"Stage"];
// items.project = [dict valueForKey:#""]; // this is the relationship for items
}
NSError *error = nil;
if (![__managedObjectContext save:&error]) {
NSLog(#"There was an error! %#", error);
}
else {
NSLog(#"created");
}
[Project addItemsObject:items];
[__managedObjectContext saveOnSuccess:^{
NSLog(#"You created a relationship");
} onFailure:^(NSError *error) {
NSLog(#"There was an error! %#", error);
}];
}
So I have one Project and many Items, I just dont know how to set up the keyfields so that they save into core data as one project and many items.
So hopefully my code is making sense. If someone could just help me figure out how to save it properly that would be greatly appreciated.
Just set items.project to be equal to the project NSManagedObject you just made
items.project = project;
EDIT: if you have only one project, you should move the Project* project declaration outside of the recivedProData for loop -- you are making one project for every dictionary, and you say you only have one project ever. That entire block of code makes no sense if you have only one project though -- why do you have an array of Project data, and not just one dictionary?
I want to discuss your Core Data model, the one you configured using the Core Data GUI editor. I'm curious about the plurality of the entity named "Items" from the following line of code:
Items *items = [NSEntityDescription insertNewObjectForEntityForName:#"Items" inManagedObjectContext:self.managedObjectContext];
Maybe it's just a matter of semantics. It's possible, however, that the plurality of that entity name indicates a problem in your Core Data model. I'll try to explain, but this is pretty abstract stuff.
Although an entity may have a relationship that represents a collection of things, the entity itself is not really a collection of things; the entity is always a single thing in the model and should be treated as such in your code (and in your naming schemes).
Here's how I would describe your model in words:
The Project entity is a single thing with a relationship called items. The items relationship is a collection (a set) of Item entities (i.e., a one-to-many relationship). But each Item entity is a single thing.
Does your model in the GUI editor reflect this description?

NSDictionary and Core Data

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.

Resources