Core Data fetch operation is slow with a Read-only sqlite database. Can I improve its performance?
Background: I have a core-data model with 2 configurations. One for the default application store, and another for seed-data (SeedData.sqlite). The SeedData.sqlite is placed inside the application bundle, and is setup as a Read-only store. The SeedData.sqlite contains approximately 6500 records.
This is how I setup the persistent store:
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
NSLog(#"%s", __FUNCTION__);
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Attempt to load the persistent store
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// Create the default/ user model persistent store
{
NSString *storeFileName = [JTCoreDataManager defaultStoreName];
NSString *configuration = #"AppName";
NSURL *storeURL = [[self applicationLocalDatabaseDirectory] URLByAppendingPathComponent:storeFileName];
// Define the Core Data version migration options
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:configuration
URL:storeURL
options:options
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
// Create the seed data persistent store
{
NSURL *seedDataURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"SeedData" ofType:#"sqlite"]];
NSString *configuration = #"SeedData";
// Define the Core Data version migration options
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption,
nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:configuration
URL:seedDataURL
options:options
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]); abort();
abort();
}
}
return _persistentStoreCoordinator;
}
The fetched results controller is setup like this:
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Seed"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"title" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"magicOn == %#", [NSNumber numberWithBool:YES]];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:#[sortDescriptor]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
NSError *error;
BOOL success = [fetchedResultsController performFetch:&error];
if (!success) {
NSLog(#"%#", [error localizedDescription]);
}
Related
Following this tutorial http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated, I created an empty command line application using core data to seed a database which I subsequently moved (by taking the quizgeodata.sqlite file) over to an ios application I am building. The only other step the tutorial lists for making it work is to add this code to the persistantStoreCoordinator in app delegate
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path]]) {
NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"quizgeodata" ofType:#"sqlite"]];
NSError* err = nil;
if (![[NSFileManager defaultManager] copyItemAtURL:preloadURL toURL:storeURL error:&err]) {
NSLog(#"Oops, could copy preloaded data");
}
}
(Previous steps included taking the class files (that correspond to the entities) and the ...xcdatamodel.d file into the empty command line application to make sure that the schemas would be the same). When I run the code in the empty command line application, it shows the fetched data that I imported in the log statements, so I assume by copying the quizgeodata.sqlite back to the ios application and adding that one bit of code in the persistent store coordinator, then the following code (in viewDidLoad) should fetch the data from core data, but the log statements are showing that no data's been retrieved. The log of the error in the code below says 'null' (meaning no error I assume) and when I ask xCode to print the sql statements it shows this in the console
2014-04-17 16:11:57.477 qbgeo[767:a0b] CoreData: annotation: total fetch execution time: 0.0026s for 0 rows.
so obviously there's no data in the sqlite file that I copied over. Can you explain what I might need to do to get it working?
Please note that I ran Project > Clean several times so that is not the issue
from ViewDidLoad
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Sportsquiz" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSLog(#"error %#", [error description]);
NSArray *messedUpObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (Sportsquiz *info in messedUpObjects) {
NSLog(#"correctAnswer %#", [info valueForKey:#"question"]);
NSLog(#"correctAnswer %#", [info valueForKey:#"correctAnswer"]);
}
Let's try:
The original project:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"TinMung.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSMutableDictionary *pragmaOptions = [NSMutableDictionary dictionary];
/*ATTETION: disable WAL mode*/
[pragmaOptions setObject:#"DELETE" forKey:#"journal_mode"];
NSNumber *optionYes = [NSNumber numberWithBool:YES];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
pragmaOptions, NSSQLitePragmasOption,
optionYes,NSMigratePersistentStoresAutomaticallyOption ,nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
abort();
}
return _persistentStoreCoordinator;
}
Copy sqlite file to new project and fetch. I think it will work.
I'm creating an object with the following code:
+(Checkin *) newCheckinWithId:(NSString*) checkinID forVenueId:(NSString *)venueId
{
NSManagedObjectContext * context = [[AppDelegate sharedInstance] managedObjectContext];
Checkin *ret = (Checkin *)[NSEntityDescription insertNewObjectForEntityForName:#"Checkin" inManagedObjectContext:context];
ret.checkinID = checkinID;
ret.forVenueID = venueId;
ret.date = [NSDate date];
NSError * error;
if(![context save:&error]) {
NSLog(#"Error saving!!!!!: %#", error.userInfo);
}
return ret;
}
This code works, and I can see the objects in the sqldatabase file on disk (in ~/library/iphone sim/.. whatever it is)
Here is the code I use to create my store + managed object context (I use 1 context for everything) Its basically all from a stack overflow post I found
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil)
{
return _managedObjectModel;
}
//NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
//__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
//NSArray *testArray = [[NSBundle mainBundle] URLsForResourcesWithExtension:#"momd"subdirectory:nil];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Model" ofType:#"momd"];
if( !path ) path = [[NSBundle mainBundle] pathForResource:#"Model" ofType:#"mom"];
NSURL *modelURL = [NSURL fileURLWithPath:path];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
//__managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if((_persistentStoreCoordinator != nil)) {
return _persistentStoreCoordinator;
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = _persistentStoreCoordinator;
// Set up iCloud in another thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// ** Note: if you adapt this code for your own use, you MUST change this variable:
NSString *iCloudEnabledAppID = #"[MY APP ID]";
// ** Note: if you adapt this code for your own use, you should change this variable:
NSString *dataFileName = #"foursquareaugmentation.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
NSString *iCloudDataDirectoryName = #"Data.nosync";
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud) {
NSLog(#"iCloud is working");
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
NSLog(#"iCloudEnabledAppID = %#",iCloudEnabledAppID);
NSLog(#"dataFileName = %#", dataFileName);
NSLog(#"iCloudDataDirectoryName = %#", iCloudDataDirectoryName);
NSLog(#"iCloudLogsDirectoryName = %#", iCloudLogsDirectoryName);
NSLog(#"iCloud = %#", iCloud);
NSLog(#"iCloudLogsPath = %#", iCloudLogsPath);
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil) {
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
NSLog(#"iCloudData = %#", iCloudData);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey];
[psc lock];
NSError *error;
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:&error];
if( error )
{
NSLog(#"Error adding persistent store %#, %#", error, [error userInfo]);
// comment in this line while debugging if get "Can't find model for source store" error in addPersistentStoreWithType.
// it means the sqlite database doesn't match the new model and needs to be created from scratch.
// this happens if you change the xcdatamodel instead of creating a new one under Xcode->Editor->Add Model Version...
// CoreData can only automatically migrate if there is a new model version (it can't migrate if the model simply changes, because it can't see the difference between the two models).
// be sure to back up the database if needed, because all data will be lost.
//[fileManager removeItemAtPath:iCloudData error:&error];
/*// this is another way to verify the hashes for the database's model to make sure they match one of the entries in the momd directory's VersionInfo.plist
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:[NSURL fileURLWithPath:iCloudData] error:&error];
if( !sourceMetadata )
NSLog(#"sourceMetadata is nil");
else
NSLog(#"sourceMetadata is %#", sourceMetadata);*/
}
[psc unlock];
}
else {
NSLog(#"iCloud is NOT working - using a local store");
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
NSError *error;
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
if( error )
NSLog(#"Error adding persistent store %#, %#", error, [error userInfo]);
[psc unlock];
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"SomethingChanged" object:self userInfo:nil];
});
});
return _persistentStoreCoordinator;
}
/*
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *) managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return _managedObjectContext;
}
Here is my fetch:
+(NSArray *) checkinsForVenue:(NSString *) venueID
{
NSManagedObjectContext * context = [[AppDelegate sharedInstance] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Checkin" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = entity;
//NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(forVenueID = %#)", venueID];
//request.predicate = predicate;
NSError *error;
NSArray * ret = [context executeFetchRequest:request error:&error];
if(ret == nil) {
NSLog(#"%#", error.description);
}
return ret;
}
Fetch always returns no objects (the empty array) even though there are things in the database!
I've been working on this problem for quiet a while and am pretty out of ideas so anything appreciated!
Thanks
Try this code to fetch data:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil )
{
return _fetchedResultsController;
}
NSLog(#"Length:: %d",[[_fetchedResultsController mutableCopy] length]);
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"OrderDetails"];
[fetchRequest setIncludesSubentities:YES];
// Sort by Application name
NSSortDescriptor* sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:#"orderId" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
//Sort by CommandNameloca
NSArray* sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor1, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:100];
ordersArr=[[NSMutableArray alloc]initWithArray:sortDescriptors];
NSLog(#"----- ordersArr Count == %d",[ordersArr count]);
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"orderId" cacheName:#"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
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;
}
After this method i executed write this line to store data in your app array like this:
NSMutableArray *myArr=[[NSMutableArray alloc]initWithArray:self.fetchedResultsController.fetchedObjects];
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];
I'm using Core Data in an existing application. Now I want to integrate iCloud so that the user can synchronize their contents between their iOS-devices. To do that I've written the following code for my NSPersistentStoreCoordinator (of course the placeholders are filled out in my code):
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"<DB_Name>.sqlite"];
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSPersistentStoreCoordinator* psc = persistentStoreCoordinator_;
if (IOS_VERSION_GREATER_THAN_OR_EQUAL_TO(#"5.0")) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
// Migrate datamodel
NSDictionary *options = nil;
// this needs to match the entitlements and provisioning profile
NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:#"<App_Identifier>"];
NSString* coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:#"data"];
if ([coreDataCloudContent length] != 0) {
// iCloud is available
cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
#"<App_Name>.store", NSPersistentStoreUbiquitousContentNameKey,
cloudURL, NSPersistentStoreUbiquitousContentURLKey,
nil];
} else {
// iCloud is not available
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
}
NSError *error = nil;
[psc lock];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[psc unlock];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"asynchronously added persistent store!");
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefetchAllDatabaseData" object:self userInfo:nil];
});
});
} else {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSError *error = nil;
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
return persistentStoreCoordinator_;
}
With that code all new added data records are synchronized automatically between all iOS-devices, so that works exactly the way it should!
But what I want is that also all the existing data records are synced between all devices; that doesn't work yet. The existing records are still available within the app and can be used, but they are not synchronized.
What do I need to do to get all the existing data records synced with iCloud too? I've experimented a bit with the method
migratePersistentStore:toURL:options:withType:error:
but without any success.
I'm very grateful for any help!
Look up the WWDC 2012 session Using CoreData with iCloud. They discuss this during the final section, under the topic of seeding. They also have some sample code that you can get from the site that has an example. In short, you will have to open 2 persistent stores, set a fetch size, then grab batches from the source, loop through them and add them to the new store, and at batch size intervals, save and reset. Pretty simple.
Here is my code:
- (IBAction) saveData
{
NSLog(#"saveData");
[self dismissKeyboard];
Fugitive *job = (Fugitive *)[NSEntityDescription insertNewObjectForEntityForName:#"Fugitive" inManagedObjectContext:managedObjectContext];
job.name = txtName.text;
NSError *error;
// here's where the actual save happens, and if it doesn't we print something out to the console
if (![managedObjectContext save:&error])
{
NSLog(#"Problem saving: %#", [error localizedDescription]);
}
// **** log objects currently in database ****
// create fetch object, this object fetch's the objects out of the database
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Fugitive" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSURL *storeURL = [[NSBundle mainBundle] URLForResource:#"iBountyHunter" withExtension:#"momd"];
id globalStore = [[managedObjectContext persistentStoreCoordinator] persistentStoreForURL:storeURL];
[managedObjectContext assignObject:job toPersistentStore:globalStore];
for (NSManagedObject *info in fetchedObjects)
{
NSLog(#"Job Name: %#", [info valueForKey:#"name"]);
}
[fetchRequest release];
[self.navigationController dismissModalViewControllerAnimated:YES];
}
In the console I get this error: Problem saving: The operation couldn’t be completed. (Cocoa error 1570.)
The new object is created in the tableview, but not saved thus when re-launching the app, the object disappears
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"iBountyHunter" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"iBountyHunter.sqlite"];
NSError *error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}