I have from one side the NSManagedObject event that has a relationship one to many with the Entity Contacts.My app downloads contacts from the server, once all the contacts are downloaded I want to save them in CoreData keeping the relationship. Im wondering if I can save them in one go. All the contacts in an NSArray, contactsWeb, and push them into Core Data or I have to save each one of them like this:
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
for(int i = 0; [contactsWeb count]; i++){
NSManagedObject *contact = [NSEntityDescription insertNewObjectForEntityForName:#"Contacts" inManagedObjectContext:context];
[contact setValue:[contactsWeb objectAtIndex:i] forKey:#"text"];
[contact setValue:[NSDate date] forKey:#"date"];
[[event mutableSetValueForKey:#"toContacts"]addObject:contact];
NSError *error;
if(![context save:&error]){
NSLog(#"%#", [error localizedDescription]);
}
}
Saving a managed object context means that all changes in the context are saved to the persistent store (or to the parent context, in the case of nested contexts). So you can (and should) save the context "in one go" after all contacts have been inserted and the relationships been set.
Remark: If you create managed object subclasses Contacts and Event for your entities, your code can be simplified to
Contacts *contact = [NSEntityDescription insertNewObjectForEntityForName:#"Contacts" inManagedObjectContext:context];
contact.text = [contactsWeb objectAtIndex:i];
contact.date = [NSDate date];
[event addToContactsObject:contact];
The managed object subclasses can be created in Xcode: Select the entities in the Core Data model editor and choose "Editor -> Create NSManagedObject subclass ..." from the menu.
Related
Hi i am Newbie in iOS and first time working on Core Data my task is that i have three text fields [name, email, dob] an one save button when i put data i text fields and press save button then data from text field save in core data and move to next page to show data in tableview.
I have build core data file named as CoreData.xcdatamodeld and one entity and three attributes name, email and date of birth.
-(IBAction)saveButton:(id)sender{
if (switchButton.isOn)
{
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *transaction = [NSEntityDescription insertNewObjectForEntityForName:#"Shruti" inManagedObjectContext:context];
NSManagedObject *name = [NSEntityDescription insertNewObjectForEntityForName:#"name" inManagedObjectContext:context];
NSManagedObject *email = [NSEntityDescription insertNewObjectForEntityForName:#"email" inManagedObjectContext:context];
NSManagedObject *dob = [NSEntityDescription insertNewObjectForEntityForName:#"dob" inManagedObjectContext:context];
[name setValue:self.nameTextField.text forKey:#"name"];
[email setValue:self.emailTextField.text forKey:#"email"];
[dob setValue:self.dobTextField.text forKey:#"dob"];
NSLog(#"Switch is On and data is saved in Core Data");
TableViewController *objOfView = [[TableViewController alloc]initWithNibName:#"TableViewController" bundle:nil];
[self.navigationController pushViewController:objOfView animated:YES];
}
else{
NSLog(#"Switch is Off and data not saved in Core Data");
}
}
In core data i have entity name as Shruti nad three attributes name as name email and dob.
Is it right if not then where i am wrong?
If you've set up your Entity and Attributes correctly then you should be able to add with something like this.
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *transaction = [NSEntityDescription insertNewObjectForEntityForName:#"Shruti" inManagedObjectContext:context];
[transaction setValue:self.nameTextField.text forKey:#"name"];
[transaction setValue:self.emailTextField.text forKey:#"email"];
[transaction setValue:self.dobTextField.text forKey:#"dob"];
// Save the context
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Save Failed! %# %#", error, [error localizedDescription]);
}
But it looks like you've created four different entities, rather than one entity with three attribute.
Go back to your data model file and make sure your Shruti has it's three attribute. If not simply create one by pressing "+" button, set it's name, and set it's attribute's type as "String".
And make sure to delete those Entities name, email, and dob. Hope this will help.
I have a problem with Core Data, because I don't know the best way to handle my problem:
I load a json from a server and parse the results in ManagedObjects. At first the ManagedObjects should be temporary.
But the user can put a ManagedObject to a leaflet. And then the ManagedObject should be saved to CoreData. (The object should be accessible offline)
When the user load the same objects some time later from the server, already saved ManagedObjects should be fetched.
So I don't want to put every object in CoreData / PersistantStore the user doesn't need.
First what I do is to create a background context:
__block NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.parentContext = context;
With a fetch I check if there is already a ManagedObject in the persistantstore.
If there is one, I will take this. else create a new ManagedObject in nil context.
NSArray *results = [backgroundContext executeFetchRequest:fetch error:&error];
if (!error && results.count == 1) {
myModel = [results objectAtIndex:0];
}
else {
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MyModel" inManagedObjectContext:backgroundContext];
myModel = (MyModel *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
}
And I do the same with every relationship:
if (! myModel.relation) {
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Relation" inManagedObjectContext:backgroundContext];
myModel.relation = (Relation *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:myModel.managedObjectContext];
}
Works fine so far with creating the models.
But how to save one model?
The managedObjectContext is nil. If I call save: on the managedObjectContext, it saves everything.
In my AppDelegate i wrote a function to insert a ManagedObject in the main ManagedObjectContext:
- (void)insertObjectAndSave:(NSManagedObject *)managedObject {
if (!managedObject.managedObjectContext) {
[self.managedObjectContext insertObject:managedObject];
}
[self saveContext];
}
Is this a good solution? or is there a better way to save temporary ManagedObjects in the main ManagedObjectContext?
Excellent Answered My Mundi..
Here is on more scenario to create NSManagedObject temporary, whether we can make it permanents If we want.
Create temporary object
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
Code this if you wants to save it permanently
[managedObjectContext insertObject:unassociatedObject];
NSError *error = nil;
if (![managedObjectContext save:&error])
{
//Respond to the error
}
You could not create the objects with nil context but with a "temp" context. If you want to save them, call [tempContext save:nil];. If you want to discard them, just throw away the context.
Another strategy is to avoid the complexity of multiple context altogether by adding a simple boolean attribute temp to your entity (if relationships are one-to-many, only the top level entity needs to have this). You can save by default and display only non-temp items. You can delete temp items, including all related items, immediately or periodically.
I have two entities with a to-many relationship, there can be multiple items to each list.
List
Item
Basically all I want to achieve is to to save an Item to a specific List on click.
I've figured out how to save a new list:
- (IBAction)handleBtnAddList:(id)sender
{ MyListAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newList;
newList = [NSEntityDescription
insertNewObjectForEntityForName:#"List"
inManagedObjectContext:context];
[newContact setValue:#"Shopping" forKey:#"name"];
NSError *error;
[context save:&error]; }
But how do I save an item to the newly created list "Shopping" ?
Any help appreciated. Thanks in advance!
Hi there, finally had a chance to try this out. It's working now but running into another issue. I can add a new list, but can't seem to add an item.
I looked in the sqlite database and under the 'Item' entity the column named 'zLists' is empty. How do I get a value in there that will correspond with the 'List' that the item should be under?
This is what I've got
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *list = [NSEntityDescription
insertNewObjectForEntityForName:#"List"
inManagedObjectContext:context];
[list setValue:#"Test List" forKey:#"name"];
NSManagedObject *item = [NSEntityDescription
insertNewObjectForEntityForName:#"Item"
inManagedObjectContext:context];
[item setValue:#"Test Item" forKey:#"name"];
I also tried adding this at the end but it crashes the app
[item setValue:#"Test List" forKey:#"lists"];
For my example to work with your code, you will need these prerequisites...
You have a Core Data model NSManagedObjectModel,
Within that model, you have an entity List,
Within that model and for that entity, you have two attributes listDate, and listText,
You have used Xcode to prepare (or have manually prepared) an NSManagedObject subclass for your entity List.
Instead of your line of code: [newContact setValue:#"Shopping" forKey:#"name"];...
you might choose to use dot notation to set attribute values in this manner...
newList.listDate = [NSDate date]; //sets the attribute to current date and time
newList.listText = <<some user input from (for example) a view controller>>;
or to match your syntax, you might choose to use key-value coding in this manner.
[newList setValue:[NSDate date] forKey:#"listDate"];
[newList setValue:<<some user input>> forKey:#"listText"];
I have an Android app, and now I'm making an iOS version, but I'm having some problem with the joins in CoreData.
I have the following tables:
Cidade
-cid_codigo integer primary key
-cid_nome text
-cid_nome_normalizado text
Anunciante
-anu_codigo integer primary key
-anu_nome text
-some other values
AnuncianteCidade
-cid_codigo integer
-anu_codigo integer
To get the all data from table Cidade I use the following method:
+(NSMutableArray *)getAllCidades{
NSMutableArray *retorno = [[NSMutableArray alloc] init];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Cidade" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
//WHERE CLAUSE
NSPredicate *pred = [NSPredicate predicateWithFormat:#"1 = 1"];
[request setPredicate:pred];
NSError *error;
NSArray *cidades = [context executeFetchRequest:request error:&error];
if([cidades count] == 0){
NSLog(#"Nenhuma cidade encontrada");
}else{
for(NSManagedObject *cidade in cidades){
Cidade *c = [[Cidade alloc] init];
[c initWithCodigo:[[cidade valueForKey:#"cid_codigo"] integerValue] nome:[cidade valueForKey:#"cid_nome"] nomeNormalizado:[cidade valueForKey:#"cid_nome_normalizado"]];
[retorno addObject:c];
}
}
return retorno;
}
But now, given a name from Cidade, I want to get all the data from Anunciante associated with this Cidade.
How can I do that?
Core Data is not a database. Core Data is an object graph that happens to persist to disk and one of the formats that Core Data can persist to is a database structure. This is an important distinction that will help you to work with it moving forward.
First, you cannot call just -init on a NSManagedObject. That will not work as it is not the designated initializer of NSManagedObject. I would suggest you read up on Core Data and learn how to stand up the Core Data stack.
Having said that, your Cidade objects should have a reference to Anunciante. The join table is internal to Core Data and you don't have access to it nor should you. To get all of the Anunciante objects for a Cidade object is to simply request the objects:
Given an NSArray of Cidade objects:
NSArray *objects = ...;
for (NSManagedObject *object in objects) {
NSSet *anunciantes = [object valueForKey:#"anunciante"];
}
This is assuming you have a many to many relationship defined in the Core Data model editor between the Cidade and the Anunciante entities.
In addition to Marcus' answer, I would add that a predicate "1 = 1" could be simply left out.
To insert a managed object into the context you use a NSEntityDescription class method:
Cidade *cidade = [NSEntityDescription insertNewObjectForEntityForName:#"Cidade"
inManagedObjectContext:context];
All "anunciantes" of a cidade will be conveniently available to you as a NSSet:
cidade.anunciantes
is all you need.
I use Core Data and fetch objects into a NSMutableArray:
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Item" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
self.items = [[managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
I then use this mutable array to display objects in a table view. Moreover the data in that array gets changed overtime. I would like to persist that whole array in Core Data.
My initial idea was to remove all items from Core Data and by itterating over all objects in the mutable array persist them one at a time:
- (void)persistAllItemsInCoreData{
[self clearAllItemsFromCoreData];
NSManagedObjectContext *context = [self managedObjectContext];
for(int i = 0 ; i < [items count] ; i++){
Item *item = [NSEntityDescription
insertNewObjectForEntityForName:#"Item"
inManagedObjectContext:context];
item = [items objectAtIndex:i];
}
NSError *error;
if (![context save:&error]) {
NSLog(#"Could not save data: %#", [error localizedDescription]);
}
}
Howover, that doesn't work. Is there a more elegant way to persist an NSMutableArray using Core Data?
The items in the array are already in Core Data. If you change them you just need to save them. If you add an item to that array then you need to create a new NSManagedObject instance and put it into the array.
Your code implies that you do not understand the fundamentals of Core Data. I would highly recommend reviewing the documentation on this framework to get a better understanding of it.