In CoreData, while working with background and main context I am facing issue
Context already has a coordinator; cannot replace."
I am doing reading operation on the main context and writing operation on background context also for background context I am using background Queue. can you suggest what here i am doing wrong
========================================================================
Fatal Exception: NSInternalInconsistencyException
Context already has a coordinator; cannot replace.
#interface CoreDataCustomClass()
#property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, strong) NSManagedObjectContext *mainContext;
#property (nonatomic, strong) NSManagedObjectContext *backgroundContext;
#property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#end
static CoreDataCustomClass *sharedInstance = nil;
#implementation CoreDataCustomClass
+(CoreDataCustomClass *)sharedInstance
{
#synchronized([CoreDataCustomClass class])
{
if (!sharedInstance)
{
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
return nil;
}
#pragma mark - Core Data stack
- (NSManagedObjectContext *)mainContext {
if (_mainContext.persistentStoreCoordinator) {
return _mainContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__weak __typeof(self)weakSelf = self;
_mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainContext performBlockAndWait:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf->_mainContext setPersistentStoreCoordinator:coordinator];
}];
}
return _mainContext;
}
-(void)saveMainContext {
NSManagedObjectContext *mainManagedObjectContext = self.mainContext;
[mainManagedObjectContext performBlock:^{
NSError *error = nil;
if ([mainManagedObjectContext hasChanges] && ![mainManagedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[mainManagedObjectContext performBlock:^{
NSError *error = nil;
if ([mainManagedObjectContext hasChanges] && ![mainManagedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}];
}];
}
-(NSManagedObjectContext *)backgroundContext{
if (_backgroundContext.persistentStoreCoordinator){
return _backgroundContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if(coordinator != nil){
__weak __typeof(self)weakSelf = self;
_backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_backgroundContext performBlockAndWait:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf->_backgroundContext setPersistentStoreCoordinator:coordinator];
[strongSelf->_backgroundContext setUndoManager:nil];
}];
}
return _backgroundContext;
}
-(void)saveBackgroundContext {
NSManagedObjectContext *backgrounManagedObjectContext = self.backgroundContext;
[backgrounManagedObjectContext performBlock:^{
NSError *error = nil;
if ([backgrounManagedObjectContext hasChanges] && ![backgrounManagedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[backgrounManagedObjectContext performBlock:^{
NSError *error = nil;
if ([backgrounManagedObjectContext hasChanges] && ![backgrounManagedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}];
}];
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"abc" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSDictionary *persistentOptions = #{NSMigratePersistentStoresAutomaticallyOption:#YES, NSInferMappingModelAutomaticallyOption:#YES};
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"abc.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
[[NSFileManager defaultManager] removeItemAtURL: storeURL error: nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration: nil URL: storeURL options: nil error: &error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:[storeURL path] error:&error]) {
NSLog(#"error");
}
return _persistentStoreCoordinator;
}
Related
The belowe code works perfectly on native environment but if I use it in a Mobile first generated app it crashes. Moreover it only happens when I compile the project with iOS 10 SDK, up to iOS 9 SDK it works fine.
Message sent to deallocated instance Core Data iOS 10 Mobile First 7.1
I'm getting the following error every time I try to execute a request through NSManagedObjectContext.
*** -[_PFArray count]: message sent to deallocated instance 0x1c524f060
Here's the code:
NSError *error = nil;
NSArray *matches = [self processFetchRequest:fetchRequest error:&error];
if( matches.count > 0 ){
toReturn = (User*)[matches objectAtIndex:0];
}
where:
- (nullable NSArray*) processFetchRequest:(NSFetchRequest*)fetchRequest error:(NSError**)error{
__block NSArray *matches = nil;
#synchronized (self) {
NSManagedObjectContext *context = [self managedObjectContext];
[context performBlockAndWait:^{
matches = [context executeFetchRequest:fetchRequest error:error];
}];
}
return matches;
}
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = _managedObjectContext;
if ( context == nil ) {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
}
return _managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [self getStoreURL];
NSError *errorMetadata = nil;
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *storeOptions = #{NSPersistentStoreFileProtectionKey : NSFileProtectionCompleteUntilFirstUserAuthentication};
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:storeOptions
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
I changed my existing core stack and my sqlite file doesn't get updated anymore after it's created. I'm able to save and fetch data with core data, but the sqlite file is always empty(the sqlite-shm file gets updated instead). Is my implementation wrong? What do I need to do to get my sqlite file to be updated?
//header file
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectContext *masterManagedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectContext *mainManagedObjectContext;
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator;
-(NSManagedObjectModel *)managedObjectModel;
-(NSManagedObjectContext *)masterManagedObjectContext;
-(NSManagedObjectContext *)mainManagedObjectContext;
-(NSManagedObjectContext *)workerManagedObjectContext;
//implementation file
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
#synthesize masterManagedObjectContext = __masterManagedObjectContext;
#synthesize mainManagedObjectContext = __mainManagedObjectContext;
//Managed object context
-(NSManagedObjectContext *)masterManagedObjectContext{
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[__masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __masterManagedObjectContext;
}
- (NSManagedObjectContext *)mainManagedObjectContext {
if (__mainManagedObjectContext != nil) {
return __mainManagedObjectContext;
}
__mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[__mainManagedObjectContext setParentContext:self.masterManagedObjectContext];
return __mainManagedObjectContext;
}
- (NSManagedObjectContext *)workerManagedObjectContext {
NSManagedObjectContext *tempMOContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
tempMOContext.parentContext = [self mainManagedObjectContext];
return tempMOContext;
}
//Save methods
- (void)saveWorkerContext:(NSManagedObjectContext *)context {
NSError *error;
[context save:&error];
if (!error) {
[self saveMainContext];
}
}
- (void)saveMainContext {
[self.mainManagedObjectContext performBlock:^{
NSError *error = nil;
[self.mainManagedObjectContext save:&error];
if(!error){
//Write to disk after saving on the main UI context
[self saveMasterContext];
}
}];
}
- (void)saveMasterContext {
[self.masterManagedObjectContext performBlock:^{
NSError *error = nil;
[self.masterManagedObjectContext save:&error];
if(error){
NSLog(#"CORE DATA MASTER CONTEXT ERROR : %#", error);
}
}];
}
-(NSManagedObjectModel *)managedObjectModel {
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"MyResource"
ofType:#"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
NSString *modelPath = [bundle pathForResource:#"MyData"
ofType:#"momd"];
//NSLog(#"Bundle modelURL:%#",modelPath);
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MyData.sqlite"];
//NSLog(#"storeURL:%#",storeURL);
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;
}
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
//example of trying to save data
-(void)saveDictionary:(NSMutableDictionary *)myDictionary{
NSManagedObjectContext *context = [self workerManagedObjectContext];
[context performBlockAndWait:^{
NSMutableDictionary *tmpDic = myDictionary;
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
Entity *myEntity;
if ([fetchedObjects count]>0) {
myEntity = [fetchedObjects lastObject];
}
else{
myEntity = [NSEntityDescription insertNewObjectForEntityForName:#"Entity" inManagedObjectContext:context];
}
myEntity.value = tmpDic[#"value1"]!=nil?tmpDic[#"value1"]:#"nothing";
[self saveWorkerContext:context];
}];
}
What do I need to do to get this to work?
But you also said
I'm able to save and fetch data with core data...
That's the definition of "working" with Core Data. If that works, you're done.
The SQLite shm file is the SQLite journal. It's an implementation detail of how SQLite works. You can read up on how SQLite manages its files if you're interested but it's not really relevant to what you're doing.
Simply for the time you want to generate sqlite file use the following options when you add persistent store:
#{NSSQLitePragmasOption: #{#"journal_mode": #"DELETE"}}
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
URL:self.localStoreURL
options:#{NSSQLitePragmasOption: #{#"journal_mode": #"DELETE"}}
error:nil];
Then run the application, quit, go to the application folder and in Documents your file will be updated. I hope this will help you.
I changed my exist core stack to the one recommended here:https://medium.com/soundwave-stories/core-data-cffe22efe716#.phv9wt6kd
and saving doesn't work anymore. My sqlite file is empty when I opened it, but when I try to access the data stored in it, it returned objects with data fault. Is my implementation wrong? What do I need to do to get this to work?
//header file
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectContext *masterManagedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectContext *mainManagedObjectContext;
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator;
-(NSManagedObjectModel *)managedObjectModel;
-(NSManagedObjectContext *)masterManagedObjectContext;
-(NSManagedObjectContext *)mainManagedObjectContext;
-(NSManagedObjectContext *)workerManagedObjectContext;
//implementation file
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
#synthesize masterManagedObjectContext = __masterManagedObjectContext;
#synthesize mainManagedObjectContext = __mainManagedObjectContext;
//Managed object context
-(NSManagedObjectContext *)masterManagedObjectContext{
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[__masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __masterManagedObjectContext;
}
- (NSManagedObjectContext *)mainManagedObjectContext {
if (__mainManagedObjectContext != nil) {
return __mainManagedObjectContext;
}
__mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[__mainManagedObjectContext setParentContext:self.masterManagedObjectContext];
return __mainManagedObjectContext;
}
- (NSManagedObjectContext *)workerManagedObjectContext {
NSManagedObjectContext *tempMOContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
tempMOContext.parentContext = [self mainManagedObjectContext];
return tempMOContext;
}
//Save methods
- (void)saveWorkerContext:(NSManagedObjectContext *)context {
NSError *error;
[context save:&error];
if (!error) {
[self saveMainContext];
}
}
- (void)saveMainContext {
[self.mainManagedObjectContext performBlock:^{
NSError *error = nil;
[self.mainManagedObjectContext save:&error];
if(!error){
//Write to disk after saving on the main UI context
[self saveMasterContext];
}
}];
}
- (void)saveMasterContext {
[self.masterManagedObjectContext performBlock:^{
NSError *error = nil;
[self.masterManagedObjectContext save:&error];
if(error){
NSLog(#"CORE DATA MASTER CONTEXT ERROR : %#", error);
}
}];
}
-(NSManagedObjectModel *)managedObjectModel {
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"MyResource"
ofType:#"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
NSString *modelPath = [bundle pathForResource:#"MyData"
ofType:#"momd"];
//NSLog(#"Bundle modelURL:%#",modelPath);
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MyData.sqlite"];
//NSLog(#"storeURL:%#",storeURL);
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;
}
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
//example of trying to save data
-(void)saveDictionary:(NSMutableDictionary *)myDictionary{
NSManagedObjectContext *context = [self workerManagedObjectContext];
[context performBlockAndWait:^{
NSMutableDictionary *tmpDic = myDictionary;
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
Entity *myEntity;
if ([fetchedObjects count]>0) {
myEntity = [fetchedObjects lastObject];
}
else{
myEntity = [NSEntityDescription insertNewObjectForEntityForName:#"Entity" inManagedObjectContext:context];
}
myEntity.value = tmpDic[#"value1"]!=nil?tmpDic[#"value1"]:#"nothing";
[self saveWorkerContext:context];
}];
}
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]];
});
}
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;
}