I am trying, to reset my app which uses Core Data, for this, I have written the code below
- (void) resetApplicationModel
{
// NSError *error;
NSError *error;
// retrieve the store URL
NSURL * storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"abc.sqlite"];
// lock the current context
[self.managedObjectContext lock];
[self.managedObjectContext reset];//to drop pending changes
//delete the store from the current managedObjectContext
if ([[self.managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:&error])
{
// remove the file containing the data
if([[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error])
{
//recreate the store like in the appDelegate method
if([[self.managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error] == nil)
{
NSLog( #"could not create new persistent store at %# - %#", [storeURL absoluteString], [error localizedDescription]);
}
}
else
{
NSLog( #"could not remove the store URL at %# - %#", [storeURL absoluteString], [error localizedDescription]);
}
}
else
{
NSLog( #"could not remove persistent store - %#", [error localizedDescription]);
}
[self.managedObjectContext unlock];
__managedObjectContext = nil;
[self managedObjectContext];
_rootViewController.controller = nil;//Make NSFetchResultsController nil;
}
This code works fine on ios 6.1 simulator and there are no issues, but when I check this on iphone 4 running iOS 6.1.3, the persistence file is not deleted and I get error saying
"could not remove the store URL at file://localhost/var/mobile/Applications/147E198E-FAB9-46EA-BE4B-4411AFA013FB/Documents/abc.sqlite - The operation couldn’t be completed. (Cocoa error 4.)"
But all the data is deleted, Now when I try to add new Data inside coreData , I get a error saying
" Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.'"
Please help me guys
Regards
Ranjit
Create a category on NSManagedObjectContext then implement:
- (BOOL)deleteAllObjectsForEntityName:(NSString *)entity withError:(NSError *__autoreleasing *)error {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:entity inManagedObjectContext:self]];
[request setIncludesPropertyValues:NO];
NSArray *allObjects = [self executeFetchRequest:request error:error];
if (![self save:error])
return NO;
for (NSManagedObject *object in allObjects)
[self deleteObject:object];
return YES;
}
Then to use this simply do:
- (void)deleteAllObjectsForEntityName:(NSString *) entity {
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if (![managedObjectContext deleteAllObjectsForEntityName:entity withError:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
}
Pass your entity name in and it will delete it all :-)
Related
Application crashes while inserting the data into core data.
There are more then 500 records going to insert into the database. Initially check condition if messageId not exit in database then insert the record in database.
But application crash on
BOOL isExist = [context countForFetchRequest:request error:&error];
with the error Collection <__NSCFSet: 0x16f601c0> was mutated while being enumerated.'
appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = appDelegate.managedObjectContext;
__block NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
__block NSManagedObjectContext *writerObjectContext = appDelegate.writerManagedObjectContext;
__block NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = managedObjectContext;
[temporaryContext performBlockAndWait:^{
NSError *error;
for (StreamData *stream in streamData) {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:DB_TABLE_STREAM];
[request setPredicate:[NSPredicate predicateWithFormat:#"stream_id = %#", stream.messageId]];
[request setFetchLimit:1];
BOOL isExist = [context countForFetchRequest:request error:&error];
if (!isExist) {
CF_Stream *object = [NSEntityDescription insertNewObjectForEntityForName:DB_TABLE_STREAM inManagedObjectContext:context];
[object setStream_id:[NSNumber numberWithLongLong:[stream.messageId longLongValue]]];
[object setType:stream.streamType];
[object setTime_stamp:[[DateTimeManager sharedInstances] getStreamDate:stream.streamTime]];
}
if (![temporaryContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
if (![temporaryContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[managedObjectContext performBlock:^{
NSError *error = nil;
if (![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[writerObjectContext performBlock:^{
NSError *error = nil;
if (![writerObjectContext save:&error]) {
completionBlock(NO);
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
} else {
completionBlock(YES);
}
}];
}];
}];
This is My code:
This is iCloud with Coredata synchronization configuration code:
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.wanglichen.iPassword" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"iPassword" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// create a new persistent store of the appropriate type
NSError *error = nil;
NSURL *storeURL = [self applicationDocumentsDirectory];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
// ** Note: if you adapt this code for your own use, you MUST change this variable.
// is the full App ID (including the Team Prefix). You will need to change this to match the Team Prefix found in your own iOS Provisioning Portal.
NSString *iCloudEnabledAppID = [[NSBundle mainBundle] infoDictionary][#"CFBundleIdentifier"];
// the name of the SQLite database store file.
NSString *dataFileName = #"iPassword.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
// dataDirectory is the name of the directory the database will be stored in. It should always end with .nosync
// iCloudData = iCloudRootPath + dataDirectory
NSString *iCloudDataDirectoryName = #"Data.nosync";
// logsDirectory is the name of the directory the database change logs will be stored in.
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [storeURL URLByAppendingPathComponent:dataFileName];
// iCloudRootPath is the URL to your apps iCloud root path.
NSURL *iCloudRootPath = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloudRootPath) // If iCloud is working, save it to iCloud container.
{
NSLog(#"iCloud is working.");
// Place core data sqlite file in iCloudRootPath/Data.nosync/ (The subdirectory should be ended with .nosync)
// Place the log file in iCloudRootPath/Logs (All changed in iCloud will be download to log file firstly.)
NSURL *iCloudLogsPath = [iCloudRootPath URLByAppendingPathComponent:iCloudLogsDirectoryName];
// NSLog(#"iCloudEnabledAppID = %#",iCloudEnabledAppID);
// NSLog(#"dataFileName = %#", dataFileName);
// NSLog(#"iCloudDataDirectoryName = %#", iCloudDataDirectoryName);
// NSLog(#"iCloudLogsDirectoryName = %#", iCloudLogsDirectoryName);
// NSLog(#"iCloud = %#", iCloudRootPath);
// NSLog(#"iCloudLogsPath = %#", iCloudLogsPath);
NSURL *iCloudDataURL = [iCloudRootPath URLByAppendingPathComponent:iCloudDataDirectoryName];
if ([fileManager fileExistsAtPath:[iCloudDataURL path]] == NO)
{
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[iCloudDataURL path]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil)
{
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
iCloudDataURL = [iCloudDataURL URLByAppendingPathComponent:dataFileName];
// NSLog(#"iCloudDataPath = %#", iCloudDataURL);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:#(YES) forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:#(YES) forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey];
[_persistentStoreCoordinator lock];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:iCloudDataURL
options:options
error:nil])
{
NSDictionary *ui = [error userInfo];
for(NSString *err in [ui keyEnumerator]) {
NSLog(#"err:%#",[ui objectForKey:err]);
}
abort();
}
[_persistentStoreCoordinator unlock];
}
else // If iCloud is not working, save it to local.
{
NSLog(#"iCloud is NOT working - using a local store");
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:#(YES) forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:#(YES) forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:#(YES) forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:#(YES) forKey:NSInferMappingModelAutomaticallyOption];
[_persistentStoreCoordinator lock];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil])
{
NSDictionary *ui = [error userInfo];
for(NSString *err in [ui keyEnumerator]) {
NSLog(#"err:%#",[ui objectForKey:err]);
}
abort();
}
[_persistentStoreCoordinator unlock];
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
// Register NSPersistentStoreDidImportUbiquitousContentChangesNotification, so that
// coreDataChangedIniCloud will be called if core data in iCloud is changed.
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(coreDataChangedIniCloud:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:self.persistentStoreCoordinator];
return _managedObjectContext;
}
- (void)coreDataChangedIniCloud:(NSNotification *)notification
{
NSLog(#"Merging in changes from iCloud...");
[self.managedObjectContext performBlock:^{
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
NSLog(#"new data from iCloud: %#", notification.object);
[[NSNotificationCenter defaultCenter] postNotificationName:#"MergingInChangesFromICloud" object:notification.object userInfo:[notification userInfo]];
}];
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = 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();
}
}
}
Here is the problem I encountered:
Crash mark
When iCloud data inside the change, I call the following method:
- (void)coreDataChangedIniCloud:(NSNotification *)notification
{
NSLog(#"Merging in changes from iCloud...");
[self.managedObjectContext performBlock:^{
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
NSLog(#"new data from iCloud: %#", notification.object);
[[NSNotificationCenter defaultCenter] postNotificationName:#"MergingInChangesFromICloud" object:notification.object userInfo:[notification userInfo]];
}];
}
This is the cause of the crash:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
performBlock (and performBlockAndWait) can only be used for NSManagedObjectContexts that were initialised with either NSPrivateQueueConcurrencyType or NSMainQueueConcurrencyType. By default NSManagedObjectContexts are initialised to use the NSConfinementConcurrencyType which does not support performBlock or performBlockAndWait.
You should change this line:
_managedObjectContext = [[NSManagedObjectContext alloc] init];
to either:
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
or
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
Try this.
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
- (void)coreDataChangedIniCloud:(NSNotification *)notification
NSManagedObjectContext *moc = self.managedObjectContext;
[moc performBlockAndWait:^{
[moc mergeChangesFromContextDidSaveNotification:notification];
}];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"MergingInChangesFromICloud" object:notification.object userInfo:[notification userInfo]];
});
}
I'm using core data and i have a problem. When i save the data and the app is still running i can see and get the data that was saved.
Once the application is close, all the fields deleted and just the object is saved. I can see that in the saveContext method.
On first launch when the app is closing the saveContext method is activated. I can see that the managedObjectContext object is inserting new object.
The next times that the app is opening , the managedObjectContext is updating the object so i know it save the objects but when i try to retrive the object it can find .
here is how i insert objects:
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
UserData *userData =[NSEntityDescription insertNewObjectForEntityForName:[UserTable tableName] inManagedObjectContext:self.managedObjectContext];
//Insert Values
userData.facebookId=user.id;
userData.name=user.name;
userData.picoAccessToken=[PicoApiManager sharedInstance].accessToken;
userData.picoExpire=[PicoApiManager sharedInstance].expires;
userData.latitude=[NSNumber numberWithDouble:user.latitude];
userData.longitude=[NSNumber numberWithDouble:user.longitude];
userData.pushId=user.pushId;
userData.isActive=[NSNumber numberWithBool:activeStatus];
}
#catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
or
-(void)addPictures:(NSMutableArray *)Pictures;
{
//Setting the isNew field to NO to all the pictures already in the db
[self updateIsNewOfPicture];
for (Picture *picture in Pictures) {
//Checks if inserted picture is already inside the table
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
PictureData *pictureData=[NSEntityDescription insertNewObjectForEntityForName:[PicturesTable tableName]inManagedObjectContext:self.managedObjectContext];
//Insert Values
pictureData.url=picture.source;
pictureData.isNew=[NSNumber numberWithBool:YES];
pictureData.isPick=[NSNumber numberWithBool:NO];
pictureData.timeTaken=picture.time_taken;
pictureData.albumData=[self getActiveAlbum];
}
#catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
}
This is app delegate functions:
- (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]);
}
}
}
#pragma mark - Core Data stack
// 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] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Pico-Db" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
// 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
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Pico.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
This is how i'm trying to get the data :
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
//2
// initializing NSFetchRequest
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//Setting Entity to be Queried
NSEntityDescription *entity = [NSEntityDescription entityForName:[UserTable tableName] inManagedObjectContext:appDelegate.managedObjectContext];
[fetchRequest setEntity:entity];
NSError* error;
// Query on managedObjectContext With Generated fetchRequest
NSArray *fetchedRecords = [appDelegate.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedRecords.count >0) {
return YES;
}
return NO;
You must call -[AppDelegate saveContext] after inserting your data in order for CoreData to persist changes to disk. The NSManagedObjectContext will store changes in memory so while your application is still active, you will have access to the data. As soon as the app terminates, however, unless you call -[AppDelegate saveContext] those changes will not be persisted.
Try this in the first example:
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
UserData *userData = [NSEntityDescription insertNewObjectForEntityForName:[UserTable tableName] inManagedObjectContext:self.managedObjectContext];
//Insert Values
userData.facebookId=user.id;
userData.name=user.name;
userData.picoAccessToken=[PicoApiManager sharedInstance].accessToken;
userData.picoExpire=[PicoApiManager sharedInstance].expires;
userData.latitude=[NSNumber numberWithDouble:user.latitude];
userData.longitude=[NSNumber numberWithDouble:user.longitude];
userData.pushId=user.pushId;
userData.isActive=[NSNumber numberWithBool:activeStatus];
} #catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
// SAVE CONTEXT:
[appDelegate saveContext];
Try this in the second example:
for (Picture *picture in Pictures) {
// Checks if inserted picture is already inside the table
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
PictureData *pictureData = [NSEntityDescription insertNewObjectForEntityForName:[PicturesTable tableName]inManagedObjectContext:self.managedObjectContext];
//Insert Values
pictureData.url=picture.source;
pictureData.isNew=[NSNumber numberWithBool:YES];
pictureData.isPick=[NSNumber numberWithBool:NO];
pictureData.timeTaken=picture.time_taken;
pictureData.albumData=[self getActiveAlbum];
} #catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
}
// SAVE CONTEXT:
[appDelegate saveContext];
To create a fetch request:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"YourEntityName"];
request.sortDescriptors = [NSSortDescriptor sortDescriptorWithKey:#"attributeName" ascending:YES];
request.predicate = [NSPredicate predicateWithFormat:#"attribute == %#", 13];
NSError *error = nil; //
NSArray *results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error];
if (!results) {
NSLog(#"Error performing fetch request: %#", error.localizedDescription);
}
return ([results count] > 0); // There are more efficient ways of getting count from CoreData
I come across a problem, every time I try to get the SQLite file using documentDirectory, I just could not find it. I really wonder where the SQLite file is put in the project file and how I can get the name of it so that I can find the SQLite file.
- (void) save
{
// Create UIManagedDocument
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentDirectory = [[fileManager URLsForDirectory:NSDocumentationDirectory inDomains:NSUserDomainMask]firstObject];
NSString *documentName = #"Model";
NSURL *url = [documentDirectory URLByAppendingPathComponent:documentName];
UIManagedDocument *document = [[UIManagedDocument alloc]initWithFileURL:url];
if ([fileManager fileExistsAtPath:[url path]]) {
[document openWithCompletionHandler:^(BOOL success) {
if (success) {
if (document.documentState == UIDocumentStateNormal) {
// Get a ManagedObjectContext
NSManagedObjectContext *context = document.managedObjectContext;
// Set managed object (entity)
NSManagedObject *aPerson = [NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:context];
// Set value for the attribute (which are "name" and "age") of the entity
[aPerson setValue:self.nameTextField.text forKey:#"name"];
[aPerson setValue:self.ageTextField.text forKey:#"age"];
// Check whether there is an error
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't save due to %#%#", error, [error localizedDescription]);
}
// Close the window
[self dismissViewControllerAnimated:YES completion:nil];
}
}
if (!success) {
NSLog(#"couldn't open document at %#", url);
}
}];
}
else {
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (success) {
if (document.documentState == UIDocumentStateNormal) {
// Get a ManagedObjectContext
NSManagedObjectContext *context = document.managedObjectContext;
// Set managed object (entity)
NSManagedObject *aPerson = [NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:context];
// Set value for the attribute (which are "name" and "age") of the entity
[aPerson setValue:self.nameTextField.text forKey:#"name"];
[aPerson setValue:self.ageTextField.text forKey:#"age"];
// Check whether there is an error
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't save due to %#%#", error, [error localizedDescription]);
}
// Close the window
[self dismissViewControllerAnimated:YES completion:nil];
}
}
if (!success) {
NSLog(#"couldn't open document at %#", url);
}
}];
}
}
Every time when I run the apps, the debugger will say that:
2014-07-29 15:41:22.476 TableAndCoreData[2502:60b] couldn't open document at file:///Users/Mike/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/DB1F0215-2BF2-43B5-ADF2-76ABC9E2CD16/Library/Documentation/Model
try this instead:
NSURL *documentDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]firstObject];
With my most recent app update, I have started to see very inconsistent SQLite errors when saving my database. These are happening with multiple users, so it is not just the same user crashing repeatedly (though it has happened for the same user multiple times). I am getting error 266, which is SQLITE_IOERR_READ. I haven't found anyone else running into this error, so not sure why I'm getting it.
00:04:18:25 $ -[AppDelegate saveContext] line 328 $ Unresolved error Error Domain=NSCocoaErrorDomain Code=266 "The operation couldn’t be completed. (Cocoa error 266.)" UserInfo=0x1dd141b0 {NSSQLiteErrorDomain=266, NSFilePath=/var/mobile/Applications/[omitted], NSPOSIXErrorDomain=1, NSUnderlyingException=I/O error for database at /var/mobile/Applications/[omitted]. SQLite error code:266, 'not an error' errno:1}, {
* 00:04:18:25 NSFilePath = "/var/mobile/Applications/[omitted].sqlite";
* 00:04:18:25 NSPOSIXErrorDomain = 1;
* 00:04:18:25 NSSQLiteErrorDomain = 266;
* 00:04:18:25 NSUnderlyingException = "I/O error for database at /var/mobile/Applications/[omitted].sqlite. SQLite error code:266, 'not an error' errno:1";
* 00:04:18:25 }
EDIT
Here is the core-data related code (most of it standard boilerplate):
/**
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] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created by merging all of the models found in the application bundle.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
//managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
// See http://iphonedevelopment.blogspot.com.au/2009/09/core-data-migration-problems.html
NSString *path = [[NSBundle mainBundle] pathForResource:#"modelDB" ofType:#"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
return managedObjectModel;
}
/**
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 {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *storePath = [[Utils documentsDirectory] stringByAppendingPathComponent: #"modelDB.sqlite"];
NSURL *storeUrl = [NSURL fileURLWithPath: storePath];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
// Allow inferred migration from the original version of the application.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
// Handle the error.
CLS_LOG(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
//Turn on complete file protection (encrypts files when phone is locked using device pin)
NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
if(![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:storePath error:&error])
{
//handle error
}
return persistentStoreCoordinator;
}
When a user logs out, this is called to remove the model store:
- (NSPersistentStoreCoordinator *)resetPersistentStore
{
NSError *error = nil;
if ([persistentStoreCoordinator persistentStores] == nil)
return [self persistentStoreCoordinator];
[managedObjectContext release];
managedObjectContext = nil;
//If there are many stores, this could be an issue
NSPersistentStore *store = [[persistentStoreCoordinator persistentStores] lastObject];
if (![persistentStoreCoordinator removePersistentStore:store error:&error])
{
CLS_LOG(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
// Delete file
if ([[NSFileManager defaultManager] fileExistsAtPath:store.URL.path]) {
if (![[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:&error])
{
CLS_LOG(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
// Delete the reference to non-existing store
[persistentStoreCoordinator release];
persistentStoreCoordinator = nil;
NSPersistentStoreCoordinator *r = [self persistentStoreCoordinator];
return r;
}
My app has a single store, so I don't think NSPersistentStore *store = [[persistentStoreCoordinator persistentStores] lastObject]; would cause an issue.
A little late to respond, but I noticed that this error almost always occurred when our app had been pushed to the background.
When creating the persistentStoreCoordinator you may need to set the NSPersistentStoreFileProtectionKey option to NSFileProtectionCompleteUntilFirstUserAuthentication instead of NSFileProtectionComplete.
Note that this slightly elevates the security risk so you may want to consider if this is necessary in your app.
Are you sure that the database is correctly opened / closed at everytime? It can be a problem due to a file open while it was uncorrectly closed