I'm currently working on an IOS app which is already developed using objective-C.
I have added a module where users when login store details about the user. But as the app is already having some code, when I press the logout button it deletes all the entities from the database. For this they are using something like the code below.
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSError *error = nil;
// retrieve the store URL
NSURL *storeURL = [[managedObjectContext persistentStoreCoordinator] URLForPersistentStore:[[[managedObjectContext persistentStoreCoordinator] persistentStores] lastObject]];
// lock the current context
[managedObjectContext lock];
[managedObjectContext reset];//to drop pending changes
//delete the store from the current managedObjectContext
if ([[managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:&error]){
// remove the file containing the data
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
//recreate the store like in the appDelegate method
[[managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store
}
[managedObjectContext unlock];
By keeping the break points, I understood that they are retrieving the url of the database and deleting it and re-creating it. Lets say they have 3 tables A,B and C, I want to delete A & B but not C. Reference- Persistent Store Coordinator
Is my understanding correct? How can I achieve this?
TIA
Try this code
NSManagedObjectContext *context = [self managedObjectContext];
[context deleteObject:managedObject];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
When user tap logout, you should clear the stored data.
First of all Fetch all the data using simple fetch store it in an array say "results"
then fetch objects in the array and remove it
for (Entity *entityOBJ in results) {
[context deleteObject:entityOBJ];
}
[context save:&error];
You have 3 tables, repeat it for 3 tables. Create a function just pass on the TableName.
I did something like below. Correct me If I'm wrong with my approach.
- (void) deleteData {
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSError *error = nil;
[managedObjectContext lock];
[managedObjectContext reset];
NSPersistentStoreCoordinator *psc = [managedObjectContext persistentStoreCoordinator];
NSManagedObjectModel *managedModel = [psc managedObjectModel];
NSArray *allEntityNames = [managedModel.entitiesByName allKeys];
for(NSString *entityName in allEntityNames)
{
//I wanted to delete all objects except for one table
if(![entityName isEqual:switchAccountsTableName])
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *objError = nil;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&objError];
if(fetchedObjects == nil)
{
NSLog(#"Logout- Couldnt delete entity objects");
}
for(NSManagedObject *entityObj in fetchedObjects)
{
[managedObjectContext deleteObject:entityObj];
}
}
}
[managedObjectContext save:&error];
[managedObjectContext unlock];
}
Related
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]);
}
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.
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();
}
}
I use core data in my application. When I delete object with [context deleteObject:obj], object is not deleted only with empty fields. How can I delete object permanently? Thanks in advanced. I use table view and when this view is filled with data from core data, there are empty rows where were deleted objects. This is the code:
LNAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
self.context = [appDelegate managedObjectContext];
self.accounts = [[NSArray alloc] init];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Accounts" inManagedObjectContext:self.context];
[fetchRequest setEntity:entity];
NSError *error;
self.accounts = [self.context executeFetchRequest:fetchRequest error:&error];
Are you making sure to save the context after you make the change?
NSError *error = nil;
if(![self.managedObjectContext save:&error])
{
/*
//Handle error
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
Also make sure that you are referencing the correct context, as you can have more than one.
My app is setup so that when it's first used, it downloads the required data from a web based xml feed.
The user also has the option to periodically refresh the data via a setting.
When they do this, I want to delete the existing database and then recreate it via the code I use for the first load.
I read that simply deleting the database is not the correct way to do this so I'm using the following to destroy the data before loading the new dataset.
- (void)resetApplicationModel {
NSURL *_storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: DBSTORE]];
NSPersistentStore *_store = [persistentStoreCoordinator persistentStoreForURL:_storeURL];
[persistentStoreCoordinator removePersistentStore:_store error:nil];
[[NSFileManager defaultManager] removeItemAtPath:_storeURL.path error:nil];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
}
However this doesn't work, when performing a data refresh, it downloads the data but can't save it to the database and generates the following error in the console;
This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.
What's the "correct" way to refresh a database?
The "right" way to do this is to just fetch all of the objects, delete each of them, and then save the context. (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html)
- (void) deleteAllEntitiesForName:(NSString*)entityName {
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:entityName inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array != nil) {
for(NSManagedObject *managedObject in array) {
[moc deleteObject:managedObject];
}
error = nil;
[moc save:&error];
}
}
Then you can just recreate your objects.