Core data objects update through loop - ios

I have a tableView showing core-data objects. On the same view there are five buttons. Each button action should update the value of an attribute from the objects.
As an example, I will show you what I have to update the attribute 'isDone':
- (IBAction)allDoneAction:(id)sender {
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
int i=0;
for (NSManagedObject *mo in context)
{
[mo setValue:#"Done" forKey:#"isDone"];i++;
}
[managedObjectContext save:nil];
}
This method throws following following exception:
NSManagedObjectContext countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x9a6b0a0
2014-01-06 19:01:43.862 To-Do Pro[679:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObjectContext countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x9a6b0a0'
What do I need to avoid the exception and obtain the desired update?
Here is my NSFetchedResultsController:
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController) return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"FavoriteThing"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"displayOrder"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]
initWithObjects:sortDescriptor, nil];
//SOLO TO-DOS DE TODAY
todayDate = [NSDate date];
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:todayDate]; // Get necessary date components
NSNumber *yearBuscado = [NSNumber numberWithLong:[components year]];
NSNumber *mesBuscado = [NSNumber numberWithLong:[components month]];
NSNumber *diaBuscado = [NSNumber numberWithLong:[components day]];
// NSString *tipourgente = #"Urgent";
// NSString *tipocolor = #"Yellow";
NSString *textoNotDone = #"Not done";
NSString *textoNotDeleted = #"Not deleted";
NSPredicate *yearPredicate = [NSPredicate predicateWithFormat:#"todoYear == %#", yearBuscado];
NSPredicate *monthPredicate = [NSPredicate predicateWithFormat:#"todoMonth == %#", mesBuscado];
NSPredicate *dayPredicate = [NSPredicate predicateWithFormat:#"todoDay == %#", diaBuscado];
NSPredicate *notDonePredicate = [NSPredicate predicateWithFormat:#"isDone== %#", textoNotDone];
NSPredicate *notDeletedPredicate = [NSPredicate predicateWithFormat:#"isSemiDeleted==%#", textoNotDeleted];
// NSPredicate *urgentPredicate = [NSPredicate predicateWithFormat:#"urgent == %#", tipourgente];
// NSPredicate *colorPredicate = [NSPredicate predicateWithFormat:#"color == %#", tipocolor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSPredicate *busqueda = [NSCompoundPredicate andPredicateWithSubpredicates:#[yearPredicate,monthPredicate,dayPredicate,notDonePredicate,notDeletedPredicate]];
[fetchRequest setPredicate:busqueda];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
[self setFetchedResultsController:aFetchedResultsController];
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}

Ok, I know absolutely nothing about core data, but from what I have researched in the last two minutes it appears as though you do not loop over An object of NSManagedObjectContext. You need to create a search within the context and get the results from that. Then iterate through the results and modify willy nilly.
Here is an example taken from this answer:
NSManagedObjectContext * context = [self managedObjectContext];
NSFetchRequest * fetch = [[[NSFetchRequest alloc] init] autorelease];
[fetch setEntity:[NSEntityDescription entityForName:#"ShoppingBasket" inManagedObjectContext:context]];
NSArray * result = [context executeFetchRequest:fetch error:nil];
for (id basket in result)
[context deleteObject:basket];
So get the context, Create a search, get an array from the context based on the search criteria, loop through the results and do as you will with updating them.

If you are using a fetchedResultsController already to populate the tableView then you can iterate over the objects in the fetchedResultsController like this:
- (IBAction)allDoneAction:(id)sender {
NSArray *objects = [fetchedResultsController fetchedObjects];
for (NSManagedObject *mo in objects) {
[mo setValue:#"Done" forKey:#"isDone"];i++;
}
NSError *error;
bool result = [[fetchedResultsController managedObjectContext] save:&error];
if (!result) {
NSLog(#" error saving context, %#, %#", error, error.userInfo);
}
}
BTW you should be checking for errors in your call to save so don't pass in nil.

Related

Error saving data in Core Data (IOS)

My program receives the JSON data from the Web service. Next, the program stores the data in the database using Core Data. If I call the save data after adding each entry, everything works, but very slowly. Keeping 200 entries takes more than one minute.
If I execute saving only once at the end – the program throw exception.
- (void) onLoadMessages:(NSObject*)object {
NSArray *messages = (NSArray*)object;
if (messages==nil) {
[self onError:#"Message array is null"];
return;
}
NSDate *date = [NSDate date];
long now = [date timeIntervalSince1970];
Boolean update = false;
for(int i=0; i<messages.count; i++) {
NSDictionary *m = messages[i];
Message *msg = [[Message alloc]initWithDictionary:m];
if ([self UpdateMessage:msg UpdateTime:now])
update = true;
}
if (update) {
NSError *error = nil;
// Error throw here
if (![self.managedObjectContext save:&error])
[self onError2:error];
}
}
- (Boolean) UpdateMessage:(Message*) msg UpdateTime:(long)now {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Messages" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSString *s = [NSString stringWithFormat:#"%ld", msg.id];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(id=%#)", s];
[fetchRequest setPredicate:pred];
NSError *error;
NSArray *object = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
Boolean result = false;
if (object==nil)
[self onError2:error];
else {
NSManagedObject *m;
if ([object count]==0) {
// Insert new message
m = [NSEntityDescription insertNewObjectForEntityForName:#"Messages"
inManagedObjectContext:self.managedObjectContext];
[m setValue:[NSNumber numberWithLong:msg.id] forKey:#"id"];
[m setValue:[NSNumber numberWithLong:msg.agancy.id] forKey:#"agancy"];
[m setValue:msg.header forKey:#"header"];
[m setValue:msg.keywords forKey:#"keywords"];
[m setValue:[NSNumber numberWithLong:msg.indate] forKey:#"indate"];
[m setValue:[NSNumber numberWithLong:now] forKey:#"updated"];
result = true;
} else {
// Update message
m = [object objectAtIndex:0];
[m setValue:[NSNumber numberWithLong:now] forKey:#"updated"];
}
// Save the context.
// Too long execution
/*NSError *error = nil;
if (![self.managedObjectContext save:&error])
[self onError2:error];*/
}
return result;
}
Help correct the behavior of the program.
With respect,
Alexander.
P.S.
Execution takes place in the main thread.
Field "Id" for table "Messages" indexed.
I solve the problem by adding privateObjectContext!
_privateObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
And replace managedObjectContext on privateObjectContext when updating/inserting data/

NSPredicate between two dates returns 0 results

I am trying to retrieve some results based on the "begin" (NSDate) field. However, it always returns 0 results.
And I can't figure out what I am doing wrong. I am guessing it has something to do with the NSDate type but I have double checked and everything seems correct.
I have checked this answer, and this one also. But to no avail…
Any help would be greatly appreciated.
Here is the definition in the model file :
#property (nonatomic, retain) NSDate * begin;
And here is the code from which I call the fetch Request.
-(void)getCalendarListForDatesFrom:(NSDate *)startDate
To:(NSDate *)endDate
inViews:(NSArray *)daysArray
{
// Reset dates to Midnight
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSUInteger preservedComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
startDate = [calendar dateFromComponents:[calendar components:preservedComponents
fromDate:startDate ]
];
endDate = [calendar dateFromComponents:[calendar components:preservedComponents
fromDate:endDate ]
];
NSLog(#"Get Events for dates %# to %#", startDate, endDate);
_isRetrievingData = YES;
NSManagedObjectContext *MOC;
NSPredicate *predicate;
NSError *error = nil;
NSString *entityName = #"CalendarEvent";
//AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//BOOL doIHaveConnexion = [appDelegate getConnexion];
MOC = self.managedObjectContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
inManagedObjectContext:MOC ];
// Fetch Request
NSFetchRequest *fetchRequest;
fetchRequest = [[NSFetchRequest alloc] init];
if (!fetchRequest)
{
fetchRequest = [[NSFetchRequest alloc] init];
}
[fetchRequest setEntity:entity];
// Filter
NSLog(#"Filter results between dates %# and %#", startDate, endDate);
predicate = [NSPredicate predicateWithFormat:#"(%K >= %#) AND (%K <= %#)", #"begin", startDate, #"begin", endDate];
//predicate = [NSPredicate predicateWithFormat:#"(%K > %#)", #"begin", [NSDate date]];
NSLog(#"PREDICATE = %#", predicate);
NSLog(#"Set Predicate");
[fetchRequest setPredicate:predicate];
NSLog(#"Set Sort Descriptor");
NSSortDescriptor *beginDateDescriptor = [[NSSortDescriptor alloc] initWithKey:#"begin"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)
];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:beginDateDescriptor, nil];
NSLog(#"Fetch");
[fetchRequest setSortDescriptors:sortDescriptors];
NSLog(#"Init Fetch");
// Initialize Fetched Results Controller
if (!self.fetchedResultsController)
{
self.fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:MOC
sectionNameKeyPath:nil
cacheName:nil ];
}
NSLog(#"Perform Fetch");
// Perform Fetch
[self.fetchedResultsController performFetch:&error];
NSArray *calEvents = [MOC executeFetchRequest:fetchRequest error:&error];
currentCalEvents = [calEvents mutableCopy];
if (error)
{
NSLog(#"Unable to execute fetch request.");
NSLog(#"%#, %#", error, error.localizedDescription);
}
else
{
NSLog(#"TOTAL CALENDAR EVENTS %lu",(unsigned long)[calEvents count]);
NSLog(#"currentCalEvents = %#", currentCalEvents);
[self addCalendarEventsToDays: daysArray];
}
fetchRequest = nil;
}
Here are the logs from the console :
Filter results between dates 2015-01-02 23:00:00 +0000 and 2015-01-07 23:00:00 +0000
PREDICATE = begin >= CAST(441932400.000000, "NSDate") AND begin <= CAST(442364400.000000, "NSDate")
Set Predicate
Set Sort Descriptor
Fetch
Init Fetch
Perform Fetch
TOTAL CALENDAR EVENTS 0

Core Data not saving an incremented integer

I'm making a SpriteKit game and I need to save the player's score using Core Data. I have a property with int value that starts off as being set to "5" and increment it x amount of times. I save it then transition to a different scene and fetch it. It shows up un-incremented with the initial value of "5".
I'm new to Core Data so forgive me if this is a stupid question, but how can I get Core Data to take the incrementation in to account? Or Is information being lost when I reference the property and how can I prevent this?
self.score = 5;
self.score++
and then save by calling this method.
AppDelegate.m
-(void) createObject {
Score *scoreEntity = (Score *)[NSEntityDescription
insertNewObjectForEntityForName:#"Score"
inManagedObjectContext:self.managedObjectContext];
SpaceshipScene *spaceshipSceneReference = [[SpaceshipScene alloc] init];
id points = [NSNumber numberWithInteger: spaceshipSceneReference.score];
scoreEntity.points = points;
scoreEntity.playerName = #"Joe";
NSError *error = nil;
// Saves the managedObjectContext
if (! [[self managedObjectContext] save:&error] ) {
NSLog(#"An error! %#", error);
}
}
This is how I call it.
SpaceshipScene.m
AppDelegate *appDelegateReference = [[AppDelegate alloc] init];
[appDelegateReference createObject];
I then fetch it in another class/scene using this method
AppDelegate.m
-(void)fetchObject {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Score"inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Sort fetched data
NSSortDescriptor *sortByPoints = [[NSSortDescriptor alloc] initWithKey:#"points" ascending:NO];
// Put them in an array
NSArray *sortDescriptor = [[NSArray alloc] initWithObjects:sortByPoints, nil];
// Pass the array to the fetch request
[fetchRequest setSortDescriptors:sortDescriptor];
NSError *error = nil;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"Problem %#", error);
}
for (Score *s in fetchedObjects) {
NSLog(#" %# %d",s.playerName, [s.points integerValue]);
}
}
This is how I call it in the final scene/class
AppDelegate *appDelegateReference = [[AppDelegate alloc] init];
[appDelegateReference fetchObject];
Hope this will work, after fetching your Score entity , simply assign new values in it don't use insert object for update any value.
[scoreEntity setPoints:[NSNumber numberWithInteger: spaceshipSceneReference.score]];
[scoreEntity setPlayerName:#"Joe"];
then Save the values:
NSError *error = nil;
// Saves the managedObjectContext
if (! [[self managedObjectContext] save:&error] ) {
NSLog(#"An error! %#", error);
}

Unrecognised selector sent to instance when trying to insert in CoreData

I am trying to save some data to CoreData but i get the error:
Restaurant Manager[5971:60b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ProdusComandat setIdProdus:]: unrecognized selector sent to instance 0x90b8270'
Can someone tell me why?
SessionController* sessionController = [[SessionController alloc]init];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"ComenziActive"];// baza de date
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"numeClient == %#",sessionController.getSessionUsername]];
NSError *err;
NSUInteger count = [self.managedObjectContext countForFetchRequest:fetchRequest error:&err];
NSArray *listaElementeBD = [[NSArray alloc]init];
if(count <= 0)
{
NSEntityDescription *entitydesc;
entitydesc = [NSEntityDescription entityForName:#"ComenziActive" inManagedObjectContext:self.managedObjectContext];
ComenziActive *comanda = [NSEntityDescription insertNewObjectForEntityForName:#"ComenziActive" inManagedObjectContext:self.managedObjectContext];
[comanda setValue:sessionController.getSessionUsername forKey:#"numeClient"];
ProdusComandat * produsComandat = [[ProdusComandat alloc]init];
produsComandat.idProdus = [[[(Produs*)produsdb objectID] URIRepresentation] absoluteString];
produsComandat.cantitateComandata = [NSNumber numberWithInteger:[self.cantitateTextField.text integerValue]];
[comanda addProduseComandateObject:produsComandat];
}
else
{
NSError *error;
listaElementeBD = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
ComenziActive *comanda = [listaElementeBD objectAtIndex: 0];
NSArray *produse = comanda.produseComandate.allObjects;
BOOL found =NO;
for(int i=0;i<[produse count];i++)
{
ProdusComandat *p =[[ProdusComandat alloc]init];
p= produse[i];
if ([p.idProdus isEqualToString:[[[(Produs*)produsdb objectID] URIRepresentation] absoluteString]]) {
p.cantitateComandata = [NSNumber numberWithInteger:[p.cantitateComandata integerValue] + [self.cantitateTextField.text integerValue]];
found = YES;
break;
}
}
if (!found) {
ProdusComandat * produsComandat = [[ProdusComandat alloc]init];
produsComandat.idProdus = [[[(Produs*)produsdb objectID] URIRepresentation] absoluteString];
produsComandat.cantitateComandata = [NSNumber numberWithInteger:[self.cantitateTextField.text integerValue]];
[comanda addProduseComandateObject:produsComandat];
}
NSLog(#"============================");
NSLog(#"%#", comanda.produseComandate );
}
NSError *error;
[self.managedObjectContext save:&error];
What I am trying to do is get the data from CoreData entity Produs and copy it's objectID to the entity ProduseComandate that has this relationship ComenziActive<----->>ProduseComandate(relationship one-to-many) if that objectID doesn't exist in the table, but if it does exist, I want to add to the value cantiate some value that I take from the TextField.
The problem was that I needed to declare it like this:
ProdusComandat *produsComandat = [[ProdusComandat alloc]initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];

fetching particular predicate from database

I have 4 CoreData database. Each actually having their own value. But it is too heavy and i would like to reduce it to 1 Database. So each time i want to pull information from the database, i can choose what to pull. I need to use NSPredicate to set the string that i want to pull izzit?
Do i set my NSPredicate like this?
NSString *value = #"Food";
NSString *wildcardedString = [NSString stringWithFormat:#"%#*", value];
[[NSPredicate predicateWithFormat:#"ANY places.type like %#", wildcardedString];
and how do i bind the NSPredicate with the fetch request sequence?
this is my fetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil)
{
return fetchedResultsController;
}
CoreDataMelakaAppDelegate *appDelegate = (CoreDataMelakaAppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"WhereTo" inManagedObjectContext:context]];
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES] autorelease];
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:sortDescriptor, nil] autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];
// NSPredicate *pred = [NSPredicate predicateWithFormat:#"(name = %#)", wher.name];
//[fetchRequest setPredicate:pred];
NSString *value = #"Nasi";
NSString *wildcardedString = [NSString stringWithFormat:#"%#*", value];
[[NSPredicate predicateWithFormat:#"ANY wher.name like %#", wildcardedString];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
return fetchedResultsController;
}
When you alter the predicate of a fetch request used by a fetched results controller (FRC), you have to create a new fetched results controller.
Your code is fine logically but it only creates a FRC once with a predicate that compiles to:
ANY wher.name like Nasi*
... each time the FRC executes its fetch, it use that exact predicate.
If you want to use a flexible predicate, you will need to create a new FRC every time you change the predicate.

Resources