Core Data wont save changes - ios

I'm having a bit of a problem with my code, I'm actually using RestKit to map various objects in core data, that works well, then I need to edit certain object, when I edit it and save the context all works very well and without problem, the trouble is when I stop de application and open it again, none of the changes I've made are saved, here is my code:
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"TaskModel.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:#"RKSeedDatabase" ofType:#"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error %#", error);
//create the managed object contexts
[managedObjectStore createManagedObjectContexts];
//Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
then this is my update method:
// Get data
// 1.- Create the request object:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *localContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
// 3.- Define the type of managed object you need:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SavedTask" inManagedObjectContext:localContext];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSPredicate *searchTasktoComplete = [NSPredicate predicateWithFormat:#"taskId == %#", self.task.taskId];
[fetchRequest setPredicate:searchTasktoComplete];
// 5.- Execute the request:
NSError *error;
NSArray *fetchedTasks = [localContext executeFetchRequest:fetchRequest error:&error];
SavedTask *taskToComplete = [fetchedTasks objectAtIndex:0];
//complete the task in core data
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM/dd/yyyy"];
NSString *date = [dateFormat stringFromDate:[NSDate date]];
[taskToComplete setRealDate:date];
[taskToComplete setFollowUp:#"100"];
[localContext refreshObject:taskToComplete mergeChanges:YES];
[localContext save:&error];
if (![localContext save:&error]) {
NSLog(#"error");
}
can anyone help me?, thanks in advance

You should use the saveToPersistentStore method
NSError *error = nil;
if(![localContext saveToPersistentStore:&error]){
NSLog(#"Failed to save to data store");
}

Try this!
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}

Related

How to update coredata value in Objective-C

I am new in iOS and I am facing a problem regarding to update value of coredata.
For Save
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *device;
if (self.device) {
// Update existing device
[device setValue:GlobalIndexPath forKey:#"key"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Device" inManagedObjectContext:context];
[newDevice setValue:GlobalIndexPath forKey:#"key"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
My code to fetch core data is
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"EntityName" inManagedObjectContext:context]];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
And to update I and using code
NSManagedObject* favoritsGrabbed = [results objectAtIndex:0];
[favoritsGrabbed setValue:#"1" forKey:#"Key"];
Update code not update it add one object.
Note - GlobalIndexPath is a name of string.
But this is not working for me any suggestion. Thanks in Advcance!
You need to save the context every time you make changes to any NSManagedObject and want it to persist. Try this:
NSManagedObject* favoritsGrabbed = [results objectAtIndex:0];
[favoritsGrabbed setValue:#"1" forKey:#"Key"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}

Restkit/CoreData - Updating an entity's attribute does not update UITableView

I have an entity Country that includes an attribute downloaded which has a default value of 0, and is NOT mapped by RestKit. I want to be able to group my tableView into sections based on this downloaded attribute. Everything works as expected, until I try to programmatically change the downloaded value myself. Code below:
Where I'm trying to set the value - my context is the mainQueueManagedObjectContext that has been passed to the controller through the AppDelegate.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Country *country = [self.fetchedResultsController objectAtIndexPath:indexPath];
[FGDataCalls downloadFieldGuide:country.countryId];
//Set up to get the thing you want to update
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"Country" inManagedObjectContext:self.managedObjectContext]];
[request setPredicate:[NSPredicate predicateWithFormat:#"countryId = %#", country.countryId]];
NSError *error = nil;
country = [[self.managedObjectContext executeFetchRequest:request error:&error] lastObject];
if (error) {
NSLog(#"Error getting the country from core data: %#", error);
}
country.downloaded = 1;
error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Saving changes to country failed: %#", error);
}
}
FetchedResultsController:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Country" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Sort using the name property.
NSSortDescriptor *sortDownloaded = [[NSSortDescriptor alloc] initWithKey:#"downloaded" ascending:NO];
NSSortDescriptor *sortName = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
[fetchRequest setSortDescriptors:#[sortDownloaded, sortName]];
// Use the sectionIdentifier property to group into sections.
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"downloaded" cacheName:nil];
_fetchedResultsController.delegate = self;
self.fetchedResultsController = _fetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
Initializing Restkit:
//Enable RestKit logging
//RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelInfo);
//RKLogConfigureByName("RestKit/CoreData", RKLogLevelTrace);
//RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
// Initialize RestKit
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:BaseURLString]];
// Initialize managed object store
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"FGDataModel" ofType:#"momd"]];
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (!success) {
RKLogError(#"Failed to create Application Data Directory at path '%#': %#", RKApplicationDataDirectory(), error);
}
objectManager.managedObjectStore = managedObjectStore;
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"FGDataModel.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
RKLogError(#"Failed adding persistent store at path '%#': %#", path, error);
}
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[managedObjectStore createManagedObjectContexts];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Setup our object mappings
[FGDataCalls setupObjectMappings:managedObjectStore withObjectManager:objectManager];
// Save the MOC
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
appDelegate.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
I've tried saving the context as many different ways at this point, including blocks, and I haven't yet had the fetchedResultsController recognize the update and even call controllerWillChangeContent: or controllerDidChangeContent:. I have successfully deleted a row using the MOC's deleteObject: method, so I have the context in the correct state. I can even get the object from my fetchedResultsController after the downloaded attribute has been set and see that it is correct, but the table never updates. Additionally, forcing the table to reload after I have changed the attribute doesn't yield any result. I know this is a specific case, but hopefully someone else has run into the same issue or can see where I'm going wrong.
Thanks!
When saving you shouldn't do
error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Saving changes to country failed: %#", error);
}
you should do
error = nil;
if (![self.managedObjectContext saveToPersistentStore:&error]) {
NSLog(#"Saving changes to country failed: %#", error);
}
That said, assuming the FRC is connected to the same context then it should see changes before they're saved. You also don't show your FRC delegate methods so there could be an issue there.

fetch request returning null after code removed that inserts data

In the code below (in ViewDidLoad), I import a JSON file into an iOS project, and then persist the data using Core Data and, at the end, perform a fetch request successfully. However, after I remove the code that imports the file and persists the data, the fetch request starts returning (null). Based on the code below, can you explain why this is happening?
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
NSError* err = nil;
NSString* dataPath = [[NSBundle mainBundle] pathForResource:#"inventorydata" ofType:#"json"];
NSArray* inventoryData = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath]
options:kNilOptions
error:&err];
if(err) NSLog(#"Error %#",[err description]);
NSLog(#"Imported Data: %#", inventoryData);
[Questions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Inventory *partsInfo= [NSEntityDescription
insertNewObjectForEntityForName:#"Inventory"
inManagedObjectContext:self.managedObjectContext];
partsInfo.name = [obj objectForKey:#"name"];
partsInfo.sku = [obj objectForKey:#"sku"];
Supplier *supplierInfo = [NSEntityDescription
insertNewObjectForEntityForName:#"Supplier"
inManagedObjectContext:self.managedObjectContext];
supplierInfo.supplierId = [obj objectForKey:#"supplierId"];
[supplierInfo setValue:[NSSet setWithObject:partsInfo ] forKey:#"partData"];
}];
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Supplier"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
self.fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (Supplier *info in self.fetchedObjects) {
NSLog(#"supplierId: %#", info.supplierId);
}
Try this.
[Questions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Inventory *partsInfo= [NSEntityDescription
insertNewObjectForEntityForName:#"Inventory"
inManagedObjectContext:self.managedObjectContext];
partsInfo.name = [obj objectForKey:#"name"];
partsInfo.sku = [obj objectForKey:#"sku"];
Supplier *supplierInfo = [NSEntityDescription
insertNewObjectForEntityForName:#"Supplier"
inManagedObjectContext:self.managedObjectContext];
supplierInfo.supplierId = [obj objectForKey:#"supplierId"];
[supplierInfo setValue:[NSSet setWithObject:partsInfo ] forKey:#"partData"];
}];
//Add this code : need to save database.
[delegate saveContext];
// You should add this method in AppDelegate.m
- (void)saveContext{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}

Objects are not saved into SQL Lite even though it says it was saved [RestKit ManagedObjectContext]

So I am having a very frustrating problem... I am fetching objects from my Django server using Restkit and the mapping is done successfully. That is fine! Now, I am trying to get that object from my SQLLite DB and change that object and save it back. For example:
_managedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"User"];
fetchRequest.predicate = [NSPredicate predicateWithFormat: #"identifier == 3"];
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"identifier" ascending:NO];
fetchRequest.sortDescriptors = #[descriptor];
NSError *error = nil;
NSFetchedResultsController *fetchedResultsController2 = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
BOOL fetchSuccessful = [fetchedResultsController2 performFetch:&error];
if (! fetchSuccessful) {
NSLog(#"%#", error.description);
}
PokaUser* user = [[fetchedResultsController2 fetchedObjects]objectAtIndex:0];
user.firstName = #"NewFirstName";
BOOL hasSaved = [user.managedObjectContext save:&error];
NSLog(#"INFO:{%s} CoreData has Saved: %# (%d)\nerror:%# | %# | %#", __FUNCTION__, (hasSaved) ? #"YES" : #"NO", hasSaved, error, [error userInfo],[error localizedDescription]);
I get the following log:
CoreData has Saved: YES (1)
error:(null) | (null) | (null)
Now, if I close my app, and REOPEN it, (or even go check the Sqllite.db myself), the changes were NOT saved. I keep getting the very first firstname.
Here is how I created my ManagedObjectContext:
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"Maindb.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:#"Maindb" ofType:#"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
Any ideas?!
Thanks!
It is necessary to call the savePersistentStore method of managed ObjectStore: [managedObjectStore.mainQueueManagedObjectContext save:&error]; [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:&error];

iOS - update managed object if matching found

I just cant seem to figure out how to update core data object after I fetch the object that I want to modify.
This is what I'm trying to do :
1) Find 1st object from core data matching predicate conditions :
NSInteger storeId = 235; //find object with this id in core data
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[self.managedObjectContext persistentStoreCoordinator]];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Store"
inManagedObjectContext:context];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %i",storeId];
[request setPredicate:predicate];
NSArray *results = [context executeFetchRequest:request error:NULL];
2) If match found, update matching object (This is where I need help) :
if (results != nil && [results count] > 0)
{
/** Not sure how to get the correct context and modify object **/
Store *matchingObject = [results objectAtIndex:0];
[context setValue:[NSNumber numberWithInteger:storeId] forKey:"id"];
}
/** Save the context */
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
//abort();
}
Thank you for any help you can provide...
Try modifying the object property directly and saving it:
matchingObject.id = [NSNumber numberWithInteger:storeId];
The object was originally fetched with context so you should be able to save your changes by calling save on context.

Resources