How to save NSArray data in coredata? - ios

I want to save my data in coredata from NSArray. How can I achieve this ?
NSArray *fetchdata = [Lockbox arrayForKey:#"fetch"];
Here, I am getting data in below form:
How can I save this data in NSManageobject?
Here is my try:
NSFetchRequest *fetchrequestforside=[NSFetchRequest fetchRequestWithEntityName:#"demo"];
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newDevice1 = [NSEntityDescription
insertNewObjectForEntityForName:#"demo"
inManagedObjectContext:context];
NSArray *fetchdata = [Lockbox arrayForKey:#"fetch"]; //
for (int i =0;i<[fetchdata count];i++){
NSString *Name = [[fetchdata objectAtIndex:i] objectForKey:#"name"];
NSString *Websitename = [[fetchdata objectAtIndex:i] objectForKey:#"websitename"];
NSString *Feedlink = [[fetchdata objectAtIndex:i] objectForKey:#"feedurl"];
NSLog(#"value:%#,%#,%#",Name,Websitename,Feedlink);
[newDevice1 setValue:Name forKey:#"name"];
[newDevice1 setValue:Websitename forKey:#"websitename"];
[newDevice1 setValue:Feedlink forKey:#"feedurl"];
NSLog(#"value:%#,%#,%#",Name,Websitename,Feedlink);
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
But with this technique I am getting an error. How can I resolve this problem?
EDIT:-
I am getting this error:
*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]:
unrecognized selector sent to instance 0x7ff262520660'

Your code treats the contents of the fetchdata array as instances of NSDictionary, but, LockBox only appears to support string contents:
-(NSArray *)arrayForKey:(NSString *)key
{
NSArray *array = nil;
NSString *components = [self objectForKey:key];
if (components)
array = [NSArray arrayWithArray:[components componentsSeparatedByString:kDelimiter]];
return array;
}
So, you need to deal with the conversion. You're probably part dealing with it already to store the original array...
But, that's why you get the error, the code expects a dictionary but actually gets a string

Do you have an object that looks like this?
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface demo : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * websitename;
#property (nonatomic, retain) NSString * feedurl;
#end
After creating an object like this (using insertNewObjectForEntityForName) try to fetch it like that:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
Btw, I would recommended you to stick to the naming conventions and call it Demo.
Cheers

I advice you to use the awesome library MagicalRecord
it save much time and very easy
here its tutorial
MagicalRecord Tutorial

Related

One-to-Many Relationship: CoreData

I'm fairly new to coredata and have been stuck on an issue.
Any assistance will be greatly appreciated.
Information:
I have a core data app with to entities;
List and Task.
List and Task have a one-to-many relationship.
Task.h
#class List;
#interface Task : NSManagedObject
#property (nonatomic, retain) NSString * task;
#property (nonatomic, retain) NSString * note;
#property (nonatomic, retain) List *list;
#end
List.h
#class Task;
#interface List : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSDate * dateCreated;
#property (nonatomic, retain) NSNumber * sortOrder;
#property (nonatomic, retain) NSSet *task;
#end
#interface List (CoreDataGeneratedAccessors)
- (void)addTaskObject:(Task *)value;
- (void)removeTaskObject:(Task *)value;
- (void)addTask:(NSSet *)values;
- (void)removeTask:(NSSet *)values;
#end
I create lists using;
NSManagedObjectContext *context = [self managedObjectContext];
if ([self.listTextField.text length] == 0) { // Quit here if no text is entered
[self dismissViewControllerAnimated:YES completion:nil];
return;
}
// Create a new list.
// Create an NSManagedObject for our database entity.
list = [NSEntityDescription insertNewObjectForEntityForName:#"List" inManagedObjectContext:context];
// Add the new task to the object (which in turns adds to our database).
[list setValue:self.listTextField.text forKey:#"name"];
// Get current date and time.
NSDate *todayDate = [NSDate date];
// Add the date to the object (which in turns adds to our database).
[list setValue:todayDate forKey:#"dateCreated"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
I can update already created lists using the code below with cellaccessorybuttontapped;
NSManagedObjectContext *context = [self managedObjectContext];
if ([self.listTextField.text length] == 0) {
// Delete object from database.
[context deleteObject:self.list];
NSError *error = nil;
// Save the action to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
} else {
// Update existing task.
[self.list setValue:self.listTextField.text forKey:#"name"];
// Get current date and time.
NSDate *todayDate = [NSDate date];
// Add the date to the object (which in turns adds to our database).
[list setValue:todayDate forKey:#"dateCreated"];
NSError *error = nil;
// Save the action to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
[self dismissViewControllerAnimated:YES completion:nil];
I can then navigate into a list.
My question is how can I then create a task for the list I have just navigated into?
It's been 2 days and I've not been able to find anything on Google.
As advised I have added;
#property (strong, nonatomic) List *selectedList;
I now have this as my Save method
NSManagedObjectContext *context = [self managedObjectContext];
// Saving a new task.
Task *task = [NSEntityDescription insertNewObjectForEntityForName:#"Task" inManagedObjectContext:context];
task.task = self.taskText.text;
task.note = self.noteText.text;
task.list = self.selectedList;
NSLog(#"The selected list is: %#", [self.selectedList description]);
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self.selectedList addTaskObject:task];
[self dismissViewControllerAnimated:YES completion:nil];
The new task is created but it is created in all lists.
Is it possible that this is working and I'm not fetching tasks based on their list?
This is my fetch request when I navigate into a list:
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create a fetch request.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Create an entity so fetch the data from.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Task" inManagedObjectContext:self.managedObjectContext];
// Set the entity of the fetch request.
[fetchRequest setEntity:entity];
// Set the amount to be fetched at a time
[fetchRequest setFetchBatchSize:20];
// Create a sort descriptor.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"task" ascending:NO];
// Attach the sort descriptor to the fetch request.
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Create a fetch result controller using the fetch request
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
theFetchedResultsController.delegate = self;
// Perform fetch.
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
// Handle error.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
return fetchedResultsController;
That is what these methods in your entity header are for:
- (void)addTaskObject:(Task *)value;
- (void)removeTaskObject:(Task *)value;
- (void)addTask:(NSSet *)values;
- (void)removeTask:(NSSet *)values;
You'll create a new task entity:
Task *t = [NSEntityDescription insertNewObjectForEntityForName:#"Task" inManagedObjectContext:context];
Then complete the fields in it as you did with your list object:
t.task = #"Whatever";
t.note = #"Whatever Note";
t.list = currentlySelectedListItem; // whatever that happens to be -- it will be a (List *)something
Then, you want to add the task object to the list:
[currentlySelectedListItem addTask:t];
Then save the context & you're done.
Key thing here is that you're effectively updating the List object by adding a task to the set of Task values contained in the NSSet. And t.list is going to contain a pointer to the parent List object.
Looks to me like you have it laid out just fine (I'm assuming the:
#property (nonatomic, retain) List *list;
Is a relationship to the parent List and not just another value you have defined; that looks to be the case).
You need to keep track of the list that you have navigated into. One way of doing it would be to create a property called as parentList like so
#property(nonatomic,strong) List *parentList
in the view controller you create a task in. And just before navigating to the view controller set this property.
In the task view controller you do a insert similar to the List object using Task *reqdTask = [NSEntityDescription insertNewObjectForEntityForName:#"Task" inManagedObjectContext:context]; and then set all the values once say Save button is pressed.
[parentList addTaskObject: reqdTask];
and ur done. This will create a Task in the task entity and map it to the List entity. Hope this helps.
**EDIT***
You need to do this [parentList addTaskObject: reqdTask]; before saving your context.
Add this in the NSFectResultsController
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"list = %#",self.parentList]];
so it will be something like this
// Create a fetch request.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Create an entity so fetch the data from.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Task" inManagedObjectContext:self.managedObjectContext];
// Set the entity of the fetch request.
[fetchRequest setEntity:entity];
// Set the amount to be fetched at a time
[fetchRequest setFetchBatchSize:20];
// Create a Predicate.
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"list = %#",self.parentList]];
//continue
this will bring the task associated with the selected list.

Get entity by name and create relationship using CoreData

I'm trying to create a relation between two entities Mensagem and Categories, but i'm getting the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for to-many relationship: property = "mensagemParaCategorias"; desired type = NSSet; given type = __NSArrayI; ...
).'
What i tried to do was: Create a entity property (categoriaAtual), then try to get the entity by name and them set the entity to the fetched results and them create the relationship .
Here is my code.
createInitialDate.h
#import <Foundation/Foundation.h>
#import "Mensagens.h"
#import "Categorias.h"
#interface createInitialData : NSObject
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic) Categorias *categoriaAtual;
-(void)createMessage:(NSString *)mensagem ComAutor:(NSString *)autor;
CreateInitialData.m
-(void)createMessage:(NSString *)mensagem ComAutor:(NSString *)autor {
Mensagens *novaMensagem = (Mensagens *)[NSEntityDescription insertNewObjectForEntityForName:#"Mensagens" inManagedObjectContext:self.managedObjectContext];
[novaMensagem setMensagem:mensagem];
[novaMensagem setAutor:autor];
NSDate *agora = [NSDate date];
[novaMensagem setDataCriada:agora];
[self categoria:#"Posts"];
novaMensagem.mensagemParaCategorias = _categoriaAtual; // This is where i try to create the relation between the 2 entities.
NSError *error = nil;
NSManagedObjectContext *context = self.managedObjectContext;
if (![context save:&error]) {
NSLog(#"Error! %#", error);
}
}
-(void)categoria:(NSString *)nomeCategoria {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Categorias" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categoria == '%#'", nomeCategoria];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [[self managedObjectContext]executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"Problem! %#", error);
} else {
NSLog(#"Objetos %#", fetchedObjects);
_categoriaAtual = fetchedObjects;
}
}
mensagemParaCategorias
is a to-many relationship but you are assigning a pointer to an object that is not an instance of NSSet. Xcode has an option to generate methods on your managed object subclasses for adding objects to a to-many relationship.

NSManagedObject fault / cannot get 'primitive' object handled by NSManagedObject

I am struggling with CoreData. I'd like to fetch the following object:
#interface Email : NSManagedObject {
}
#property (nonatomic, copy) NSString *email;
#property (nonatomic, copy) NSString *contact;
#end
..and put the result inside a NSMutableArray, but the NSString contents, (not NSManagedObjects!). This is because I am using json-framework and that engine does not allow NSManagedObjects to be passed.
These lines fetch perfom the fetch from CoreData
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Emails" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:#"email"]];
NSError *error = nil;
NSMutableArray *fetchedObjects = [[NSMutableArray alloc] init];
fetchedObjects= [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
flight.emails=fetchedObjects;
The 'flight' object is declared as follows:
#interface Flight : NSObject {
NSMutableArray *_emails;
}
#property (nonatomic, retain) NSMutableArray *emails;
With this code I am getting CoreData faults. I tried some other implementation variants, but never actually managed to have NSString objects in flight.emails, but always NSManagedObjects. What I tried was to implement a dedicated getter function in the Email NSManagedObject that copies the fetched NSString and returns the copy.
I get the idea that this is kind of a common problem, however, my research has not led to a solution on this one here.
Thanks,
Peter
From experience, setPropertiesToFetch: only works when requesting the returned objects be dictionaries. So a couple of problems in your code:
You are asking for specific property (email), but have not set the return type to dictionary. Take a look at setResultType:.
You still need to take the result and extract the email objects from it. You cannot just assign the resulting array to your emails property.
Try this:
[fetchedRequest setResultType:NSDictionaryResultType];
NSArray* results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if(error != nil || results == nil) return;
flight.emails = [results valueForKeyPath:#"email"];

Magical Record sorting error

I create a bunch of Group Entities:
for (NSString *groupID in result) {
group = [Group MR_createInContext:context];
group.groupID = [NSNumber numberWithInteger:[groupID integerValue]];
}
I then want to list them by a sort:
NSArray *groups = [Group MR_findAllSortedBy:#"groupID" ascending:TRUE inContext:context];
for (Group *group in groups) {
DLog(#"group.groupID: %#", group.groupID);
DLog(#"group: %#", group);
}
which produces the error:
-[__NSCFNumber caseInsensitiveCompare:]: unrecognized selector sent to instance 0x2595d2c0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber caseInsensitiveCompare:]: unrecognized selector sent to instance 0x2595d2c0'
My group Entity is auto generated:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Group : NSManagedObject
#property (nonatomic, retain) NSNumber * groupID;
#end
#interface Group (CoreDataGeneratedAccessors)
#end
If I do the same fetch w/out Magical Record, it woks fine:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Group"];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"groupID" ascending:TRUE selector:nil];
NSArray *sorters = [NSArray arrayWithObject:sort];
[fetchRequest setSortDescriptors:sorters];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
Any ideas why I'm getting the error?
So I checked the Magical Record repo on github (https://github.com/magicalpanda/MagicalRecord) and I didn't see the method that you are using(probably because there was a bug in the documentation regarding the sorting methods for fetching the sorted entities but I saw two other methods that are recommended for fetching sorted entities.
[entity MR_findAllSortedByProperty:#"property" ascending:YES] // single property
[entity MR_findAllSortedByProperty:#"oneProperty,secondProp" ascending:YES] // mutliple properties

Delete an object in core data

I have an entity in my core data model like this:
#interface Selection : NSManagedObject
#property (nonatomic, retain) NSString * book_id;
#property (nonatomic, retain) NSString * contenu;
#property (nonatomic, retain) NSNumber * page_id;
#property (nonatomic, retain) NSNumber * nbrOfOccurences;
#property (nonatomic, retain) NSString * next;
#property (nonatomic, retain) NSString * previous;
I have created many Selections and saved them in Core Data and now I would like to delete some selections with some criteria. For example, I would like to delete a Selection object if matches the following:
content = test
page_id = 5
book_id = 1331313
How I can do this?
What Mike Weller wrote is right. I'll expand the answer a little bit.
First you need to create a NSFetchRequest like the following:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Selection" inManagedObjectContext:context]];
Then you have to set the predicate for that request like the following:
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"content == %# AND page_id == %# AND book_id == %#", contentVal, pageVal, bookVal]];
where
NSString* contentVal = #"test";
NSNumber* pageVal = [NSNumber numberWithInt:5];
NSString* bookVal = #"1331313";
I'm using %# since I'm supposing you are using objects and not scalar values.
Now you perform a fetch in the context with the previous request:
NSError* error = nil;
NSArray* results = [context executeFetchRequest:fetchRequest error:&error];
results contains all the managed objects that match that predicate.
Finally you could grab the objects and call a deletion on them.
[context deleteObject:currentObj];
Once done you need to save the context as per the documentation.
Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.
Hence
NSError* error = nil;
[context save:&error];
Note that save method returns a bool value. So you can use an approach like the following or display an alert to the user. Source NSManagedObjectContext save error.
NSError *error = nil;
if ([context save:&error] == NO) {
NSAssert(NO, #"Save should not fail\n%#", [error localizedDescription]);
abort();
}
You should perform a fetch request using an NSPredicate with the appropriate conditions, and then call the deleteObject: method on NSManagedObjectContext with each object in the result set.
In addition to Mike Weller and flexaddicted, after calling [context deleteObject:currentObj]; you need to save: context:
NSError *error = nil;
[context save:&error];
As from documentation:
Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.
That made matter in my case.

Resources