iphone core data loop array and save each - iphone

I have a core data model with two tables (meal and ingredients). I am trying to save ONE meal with MANY ingredients. I have the code below which loops through an array of ingredients. I'm trying to save it, but I cannot redeclare the "entity" below. How do I do it? I've tried releasing it, but that didn't work! Thanks for any help.
for (x=0;x<ingredients;x++) {
NSEntityDescription *entity = [NSEntityDescription insertNewObjectForEntityForName:#"Ingredient" inManagedObjectContext:managedObjectContext];
entity.name = #"test";
}
(this method does work saving ONE record out of the loop.. so that's not the problem)

You don't insert entities into contexts. You insert managed objects into contexts.
You should have something like:
NSManagedObject *myMO;
for (x=0;x<ingredients;x++) {
myMo = [NSEntityDescription insertNewObjectForEntityForName:#"Ingredient" inManagedObjectContext:managedObjectContext];
[myMO setValue:#"test" forKey:#"name"];
}
Of course, if have an NSManagedObject subclass you can just set the 'name' property directly.
The important thing is not confuse entities with instances of NSManagedObject or its subclasses. Entities are just descriptions of how objects relate to each other inside the object graph of the managed object context. The context uses the entity descriptions to figure out how all the actual instances fit relate to one another and how they are fetched and stored.

Related

How to model my Core Data entity?

I want to store NoteObjects in Core Data. Normally, a NoteObject has a NSString *mainText and an NSMutableArray *arrayOfTags (an array of NSStrings). I want to now use Core Data, but arrays are a tricky matter with core data. Typically a NoteObject won't have more than 50 tags in its array. So how should I model this? I have two options:
Use a transformable property to store the array
Use a to-many relationship, which I've read is the more "legit" way to do it.
Which one should I use and why? And how would I implement a to-many relationship with my simple structure? I can't seem to wrap my fingers around that concept.
Use to-many relationship. Because it's way better and easier during fetch requests. See the screenshots below. Pay attention to the Relationship manager on the right side, set "To-Many Relationship" from your NoteObject to Tags. Ignore the Player entity.
Oh and pay attention to the "Delete Rule". You might want to delete all the tags associated with a given NoteObject. So set it to Cascade in that case.
NoteObject entity
Tag entity
--Edit:
To add multiple tags you need to first fetch your NoteObject - I assume there will be some sort of ID parameter which you'll use to distinguish NoteObjects. CoreData will automatically generate the add/remove methods for Tags. You'll need to use code similar to the one below:
- (void)addTags:(NSArray *)tags toNoteObjectWithID:(NSString *)noteID {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"NoteObject"];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"noteID == %#", noteID];
[fetchRequest setPredicate:pred];
NoteObject *noteObject = [[[self managedObjectContext] executeFetchRequest:fetchRequest error:nil] lastObject];
for (NSString *tag in tags) {
Tag *t = [NSEntityDescription insertNewObjectForEntityForName:#"Tag"
inManagedObjectContext:[self managedObjectContext]];
t.body = tag;
t.noteObject = noteObject;
[noteObject addTagsObject:t];
}
[self saveContext];
}
You could use a transformable property, but then you need to write the transformer.
If you use a toMany relationship, you have to create an additional entity for tags, which presumably has only one attribute - the string value, and a single relationship. Extrapolating a little, I would guess that you have a finite set of values tags can take on, and you might someday want all notes that have tag X - then you would be able to fetch the entity containing the string value for X and then use that to fetch the NSArray of objects that have X in the relationship (whatever you called it).
Arrays were only tricky in Core Data because they weren't supported prior to iOS 5, so you had to include some attribute (like creation date) by which they could be sorted. If you don't mind requiring iOS 5, you can use ordered relationships. Results are returned in an NSOrderedSet, which is a lot like (and can can be converted to) an array. Or, just re-think the problem -- is the order of the tags on a note important to the note or the user? Would it be okay if you just display the tags in alphabetical order? If so, even better -- just use a plain old (unordered) to-many relationship.

CoreData basics – to-many relationship array data

As I am fairly new to CoreData and coming from a MySQL-DB background, the CoreData Moddeling is kind of hard to understand at some point. I am sure you can help me out with this basic question.
CoreData model-descripton:
My database-model basically consists of two entities. The first one is called "Manager", the second one is called "Zipcodes". The "Manager" has 3 attributes, which are negligible at the moment. The important thing in my opinion is here the relationship called "zipcodes". The "Zipcodes"-Entity has an attribute called zip, which is a 16 int. It has a relationship as well, called "manager".
No I'll get to the point: Each manager has multiple zicodes in which he is responsible for all sales. The problem is now that I've setup an manager entity and want to link multiple ziplcodes to him. The zipcodes per manager are seperated in one comma seperated string. (12345,56789,...)
First of all I am creating an Manager Entity.
Manager *manager = [NSEntityDescription insertNewObjectForEntityForName:#"Manager" inManagedObjectContext:self.managedObjectContext];
The next step is seperating all zicodes to an array.
Manager *manager = [NSEntityDescription insertNewObjectForEntityForName:#"Manager" inManagedObjectContext:self.managedObjectContext];
NSArray *zipcodesArray = [[dict objectForKey:#"zipcodes"] componentsSeparatedByString:#","];
for (NSString *zip in zipcodesArray) {
???
}
So now that's the point where I am stuck. As later on I have to check the zipcodes via a searchBar they should be separated in the database. Do I now have to create a managedObjectModel for each zipcode? How do I connect all of them with the "one" manager entity? I'am sure there is a way to achieve that but I don't really know how.
Hopefully my question is understandable. If there's anything you would like to know, feel free to ask.
Thank you guys!
for (NSString *zip in zipcodesArray) {
NSManagedObject* zipcode = [NSEntityDescription insertNewObjectForEntityName:#"Zipcode"
inManagedObjectContext:self.managedObjectContext];
[zipcode setValue:zip forKey:#"zip"];
[zipcode setValue:manager forKey:#"manager"];
}
By establishing the relation from the zipcode to the manager on the last line, Core Data will automatically take care of inserting the zipcode into the relation from the manager back to the zipcodes.
Create a managed object instance of Zipcode. Set that object's zip attribute to the value of the string from your zipcodesArray. When you're done, save the managed object to your data store, check for errors, and repeat until you've walked all the way through your zip code array.

NSFetchedResultsController and Relationship

This time I get a strange behavior with NSFetchedResultsController. I create a fetchRequest like this:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entdesc = [NSEntityDescription entityForName:#"Exam" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entdesc];
NSPredicate *predi = [NSPredicate predicateWithFormat:#"student == %#", self.student];
[fetchRequest setPredicate:predi];
If I execute it with executeFetchRequest:error: of NSManagedObjectContext, I get the expected Result. All Exams according to the student. (Between Student and exam is a one-to-many relationship)
But If I use the same fetchRequest in a NSFetchedResultsController, I get something different. Until now I didn't get out, what I exactly get. In my eyes the result is random.
Can you help me? I want to manage the exams of a given student with a NSFetchedResultsController.
Sandro Meier
If you have a Student object already in hand, you don't have to fetch the Exam objects you just ask the Student object for the contents of its exams relationship. There is no need to fetch because you already have a reference to all the Exam objects you want.
As to why the fetch works outside the fetch results controller, I can't say with certainty. The controller does nothing but take the results of a fetch and package them for display in a tableview. If the data does not display properly in the tableview, then the problem is most likely in the tableview delegate/datasource methods where you connect the contents of the fetched results controller to tableview.

Editing Core Data row from entity linked to managedObjectContext via relationship

I need to edit a row of data in an Entity that has a relationship with my main Entity from my fetchedResultsController, in this case "theUser" being an instance of my User entity.
I basically need to edit one of the CannedMessage rows that already exist and save it. I can access the "Messages" fine as you see below, but am unsure once I have found the CannedMessage I want as to how I save it back into the managedObjectContext for "theUser"
Any advice?
NSArray *msgs = [theUser.Messages allObjects];
NSPredicate *activeMatch = [NSPredicate predicateWithFormat:#"defaultMessage == 1"];
NSArray *matched = [msgs filteredArrayUsingPredicate:activeMatch];
CannedMessage *msgToEdit;
for(CannedMessage *msg in matched) {
msgToEdit = msg;
}
Your trouble is that your thinking in SQL terms instead of Core Data's object oriented terms. The data you are looking for is not in an SQL row but in the attribute of a managed object. In this case (I assume) you are looking for an attribute of a CannedMessage instance.
The matched array will contain either managed objects initialized with the CannedMessage entity or an instance of a dedicated NSManagedObject subclass (if you setup one which it looks like you did.)
Lets say the attribute is named theMsg. To access the attribute in the generic managed objects:
for(CannedMessage *msg in matched) {
msgToEdit = [msg valueForKey:#"theMsg"];
}
... to access a custom class:
for(CannedMessage *msg in matched) {
msgToEdit = msg.theMsg;
}
It's really important when learning Core Data to simply forget everything you know about SQL. Nothing about SQL truly translates into Core Data. Core Data is not an object-oriented wrapped around SQL. Entities are not tables, relationships are not link tables or joins, attributes are not columns and values are not rows. Instead, Core Data creates objects just like you would if you manually wrote a custom class to model a real world object, event or condition. Core Data uses SQL almost as an after thought as one of its many persistence options.
In my experience, the more you know about SQL, the harder it is to shift gears to Core Data and other object graph APIs. You want to translate the new stuff to what you have already mastered. It is natural but resist the urge.

Adding string to a tableview iphone sdk

i created a new project with a tableview already done by default with the add button which add dates. But the project is im not familiar with the nsmanagedobject thing. I want to add specific string to this not dates. thx for help!!
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
[newManagedObject setValue:[NSDate date] forKey:#"timeStamp"];
It sounds like you need to learn about Core Data. I would also recommend Core Data: Apple's API for Persisting Data on Mac OS X by Marcus S. Zarra.
To display a string, rather than a date, you need to modify the data model. The template created a data model with a sigle Event entity that has a data attribute.
You can remove or rename this entity and modify the attributes as desired. You want to add a string attribute.
Then, you will want to specify the name of your new string attribute as the key for sorting in the fetch. You will also want to use it to set the value of the text in the table view cell's text label. Finally, you will need to modify the insert new object method to set a default value for the new attribute.
Looks like you've started a project using Core-Data. If you don't know what Core-Data is or how to use it, you can find out more here:
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/CoreData/CoreData.pdf