NSManagedObjectContext returning nil iphone - iphone

I created a class ServerModel for my app and in it I want to make a connection to the Sqlite database I have on the device, but anytime I go to check my NSManagedObjectContext it is returning null.
While the same work well in my other class RootViewController
In my appdelegate I am doing
rootViewController.managedObjectContext = self.managedObjectContext;
serverModel.managedObjectContext = self.managedObjectContext;
#pragma mark -
#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 appalication.
*/
- (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];
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 = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"Data.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible
* The schema for the persistent store is incompatible with current managed object model
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}

NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"Data.sqlite"]];
What is the value of storeUrl after this line is executed? i.e. are you certain that Data.sqlite exists in your application's Documents directory?
Does all this code exist in your application delegate? If you set a breakpoint at the top of your managedObjectContext method, does the breakpoint get hit? After it gets hit, and you step through the code, which line is failing?

Related

Core Data: UIManagedDocument or AppDelegate to setup core data stack?

I am a little confused about where to setup my Core data Stack. In the Appdelegate or using a shared instance of UIManagedDocument, described here?: http://adevelopingstory.com/blog/2012/03/core-data-with-a-single-shared-uimanageddocument.html
Right now I have by core data stack setup in my AppDelegate and I am passing my MOC around between the viewcontrollers. But would it be better to migrate to UIManagedDocument and make a shared Instance, so I don't have to pass the MOC around all the time? And also because its newer?
UIManagedDocument is used to sync data (typically files) to iCloud. It is only tangentially related to Core Data.
Core Data setup is typically done in the AppDelegate so there is nothing wrong with what you are doing there. In fact, if you create a new project using Core Data that is how the Xcode template will do it.
You usually do not need to pass your ManagedObjectContext around from viewcontroller to viewcontroller. It is better to create a singleton Data Access layer which can provide context anywhere in your app. There are some cases where you might want to have a private MOC for a viewcontroller, but not very often.
Here's some code to create a singleton DataAccessLayer:
DataAccessLayer.h
#interface DataAccessLayer : NSObject
//Saves the Data Model onto the DB
- (void)saveContext;
//DataAccessLayer singleton instance shared across application
+ (id) sharedInstance;
+ (void)disposeInstance;
// 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 *)context;
#end
DataAccessLayer.m
#import "DataAccessLayer.h"
//static instance for singleton implementation
static DataAccessLayer __strong *manager = nil;
//Private instance methods/properties
#interface DataAccessLayer ()
// 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.
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
#property (readonly, strong, nonatomic) NSManagedObjectModel *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.
#property (readonly,strong,nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory;
#end
#implementation DataAccessLayer
#synthesize managedObjectContext = __managedObjectContext;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
//DataAccessLayer singleton instance shared across application
+ (id)sharedInstance
{
#synchronized(self)
{
if (manager == nil)
manager = [[self alloc] init];
}
return manager;
}
+ (void)disposeInstance
{
#synchronized(self)
{
manager = nil;
}
}
+(NSManagedObjectContext *)context
{
return [[DataAccessLayer sharedInstance] managedObjectContext];
}
//Saves the Data Model onto the DB
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
//Need to come up with a better error management here.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
// 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:#"Model"
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:#"MyData.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];
}
#end
Any time you need context, you can grab it using:
NSManagedObjectContext *context = [DataAccessLayer context];
This design generally works well. NSManagedObjectContext is a very lightweight object, so there isn't a real performance penalty keeping it around. However, if you need to do Core Data stuff on other threads, the design needs to change a bit. From Apple's docs:
You must create the managed context on the thread on which it will be
used. If you use NSOperation, note that its init method is invoked on
the same thread as the caller. You must not, therefore, create a
managed object context for the queue in the queue’s init method,
otherwise it is associated with the caller’s thread. Instead, you
should create the context in main (for a serial queue) or start (for a
concurrent queue).
Using thread confinement, you should not pass managed objects or
managed object contexts between threads. To “pass” a managed object
from one context another across thread boundaries, you either:
Pass its object ID (objectID) and use objectWithID: or existingObjectWithID:error:
on the receiving managed object context. The corresponding managed objects must have
been saved—you cannot pass the ID of a newly-inserted managed object to another context.
Execute a fetch on the receiving context.
The singleton method above is very slick. A much simpler approach is to treat the appDelegate as a singleton, which it is. Create the properties in your appDelegate then a version of the following line will retrieve the one you want. For example to retrieve the moc
self.managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel

When i am running my app, i am getting
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel
but i have my Songs class in my app and i have the following in my delegate
- (void)awakeFromNib {
RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
rootViewController.managedObjectContext = self.managedObjectContext;
}
- (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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark -
#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_;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:#"PoemSubscription" ofType:#"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
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:#"PoemSubscription.sqlite"];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
#pragma mark -
#pragma mark Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}
- (void)dealloc {
[managedObjectContext_ release];
[managedObjectModel_ release];
[persistentStoreCoordinator_ release];
[navigationController release];
[window release];
[super dealloc];
}
but still i am getting the above error ( my application type is uitabbarcontroller ).
pls let me know what is the error
Probably something is nil in your initialization methods. You should debug through the core data initialization lines to see where the problem is...
This simpler init doesn't work for you ?
managedObjectModel_ = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

iOS: EXC_ARM_DA_ALIGN in generated CoreData code

I feel like I'm starting to lose my sanity over this issue.
I've begun work on a CoreData iOS app, using the generated CoreData code that the SDK provides. My issue arises whenever I attempt to instantiate a new instance of an entity so that I can save it.
Here's the instantiation code I have, per the Apple CoreData tutorial, inside my AppDelegate (I've moved a bunch of my code there just to try to debug this issue):
NSManagedObjectContext* context = [self managedObjectContext];
if (!context)
{
NSLog(#"Error"); // I'm not too concerned about my error handling just yet
}
Right after that, here's the line that produces the error I'm experiencing:
Vehicle* vehicle = (Vehicle*)[NSEntityDescription insertNewObjectForEntityForName:#"Vehicle" inManagedObjectContext:context];
The error in question is:
Thread 1: EXC_BAD_ACCESS (code=EXC_ARM_DA_ALIGN address=0xdeadbeef)
All in all, I don't really know what that means other than there's a memory alignment issue (common with ARMv7?) and the resources I've found on Google haven't helped me in the slightest.
The only other relevant piece of code is the 'managedObjectContext' method provided by Xcode when it generates the project, because that's what generated the managedObjectContext in the first place:
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
Like I said, I'm way out of my depth here. Can anyone offer a bit of clarity as to how I could possibly resolve this?
It is likely that __managedObjectContext was not initialized (hence has value of 0xdeadbeef) which cause EXC_ARM_DA_ALIGN as side effect when try to read value from it.
#Kenny Winker
EXC_ARM_DA_ALIGN is normally come from access pointer value that is not actual type. e.g.
char buf[8];
double d = *((double *)buf); // this may cause EXC_ARM_DA_ALIGN
but it may also be caused invalid valid in pointer, which in this case, 0xdeadbeef. e.g.
double *ptr; // not initialized
double d = *ptr; // this is undefined behaviour, which may cause EXC_ARM_DA_ALIGN or other error
It is generally hard to debug these kind of bugs, here are some tips:
Check all pointer cast (i.e. (double *)(void *)ptr) and try to avoid them when possible.
Make sure everything is initialized.
When it crashed, find out which variable cause it crash and try to trace back to find out where is the value come from. Use debugger to watch a memory location can be helpful to find out all changes to a variable.
I thought it might be helpful to show a core data stack that is in operation. I will also show a part of the object diagram..
pragma mark -
#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 {
// NSLog(#"%s", __FUNCTION__);
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 a starter file.
*/
- (NSManagedObjectModel *)managedObjectModel {
//NSLog(#"%s", __FUNCTION__);
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DreamCatching" withExtension:#"mom"];
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 {
//NSLog(#"%s", __FUNCTION__);
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"DreamCatching.sqlite"];
// If the expected store doesn't exist, copy the default store.
//COMMENT / UNCOMMENT THIS TO LOAD / NOT LOAD THE STARTER FILE.
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storePath]) {
NSError *error;
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"Starter" ofType:#"sqlite"];
if ([[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:storePath error:&error])
NSLog(#"Copied starting data to %#", storePath);
else
NSLog(#"Error copying default DB to %# (%#)", storePath, error);
}
// to below here
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Error - App Delegate Creating DB %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
#pragma mark -
#pragma mark Application's Documents directory
/**
Returns the path to the application's Documents directory.
NB SETTINGS ARE NOT IN THIS DIRECTORY, THEY ARE IN THE APPS BUNDLE. CONTROL-CLICK THE APP TO SEE CONTENTS, CONTROL-CLICK THE BUNDLE TO SEE THE PREFS
*/
- (NSString *)applicationDocumentsDirectory {
//NSLog(#"%s", __FUNCTION__);
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
and the model:

iOS 5 Core Data freeze

I try to do the following simple thing:
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
Nothing fancy. But this freezes in iOS 5, it works fine in iOS 4. I don't get exceptions, warnings or errors; my app just simply freezes.
Please help me out! I'm dying here! ;)
I don't know if you also use different Thread. If yes the issue comes from the fact that NSManagedObjects themselves are not thread-safe. Creating a ManagedContext on the main thread and using it on another thread freezes the thread.
Maybe this article can help you :
http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/
Apple has a demo application for handling Coredata on several threads (usually main & background threads) : http://developer.apple.com/library/ios/#samplecode/TopSongs/Introduction/Intro.html
What I've done to solve this issue is :
In the application delegate : create the persistent store (one for all thread) and create the Coredata managed Context for the main thread,
In the background thread, create a new managed context (from same persistent store)
Notifications are used when saving, to let the mainContext know when background thread has finished (inserting rows or other).
There are several solutions, using a NSQueueOperation. For my case, I'm working with a while loop. Here is my code if it may help you. However, Apple documentation on concurrency and their Top Songs example application are good points to start.
in the application delegate :
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.cdw = [[CoreDataWrapper alloc] initWithPersistentStoreCoordinator:[self persistentStoreCoordinator] andDelegate:self];
remoteSync = [RemoteSync sharedInstance];
...
[self.window addSubview:navCtrl.view];
[viewController release];
[self.window makeKeyAndVisible];
return YES;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator == nil) {
NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
NSLog(#"Core Data store path = \"%#\"", [storeUrl path]);
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSError *error = nil;
NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
NSAssert3(persistentStore != nil, #"Unhandled error adding persistent store in %s at line %d: %#", __FUNCTION__, __LINE__, [error localizedDescription]);
}
return persistentStoreCoordinator;
}
-(NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext == nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return managedObjectContext;
}
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator == nil) {
NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
NSLog(#"Core Data store path = \"%#\"", [storeUrl path]);
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSError *error = nil;
NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
NSAssert3(persistentStore != nil, #"Unhandled error adding persistent store in %s at line %d: %#", __FUNCTION__, __LINE__, [error localizedDescription]);
}
return persistentStoreCoordinator;
}
-(NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext == nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return managedObjectContext;
}
-(NSString *)persistentStorePath {
if (persistentStorePath == nil) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths lastObject];
persistentStorePath = [[documentsDirectory stringByAppendingPathComponent:#"mgobase.sqlite"] retain];
}
return persistentStorePath;
}
-(void)importerDidSave:(NSNotification *)saveNotification {
if ([NSThread isMainThread]) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
} else {
[self performSelectorOnMainThread:#selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
}
}
In the object running the background thread :
monitor = [[NSThread alloc] initWithTarget:self selector:#selector(keepMonitoring) object:nil];
-(void)keepMonitoring{
while(![[NSThread currentThread] isCancelled]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//creating the cdw here will create also a new managedContext on this particular thread
cdwBackground = [[CoreDataWrapper alloc] initWithPersistentStoreCoordinator:appDelegate.persistentStoreCoordinator andDelegate:appDelegate];
...
}
}
Hope this help,
M.
Thanks for the hints given in this page on how to solve this freezing issue which appeared on upgrading from iOS4. It has been the most annoying problem I have found since I started programming on iOS.
I have found a quick solution for cases where there are just a few calls to the context from other threads.
I just use performSelectorOnMainThread:
[self performSelectorOnMainThread:#selector(stateChangeOnMainThread:) withObject: [NSDictionary dictionaryWithObjectsAndKeys:state, #"state", nil] waitUntilDone:YES];
To detect the places where the context is called from another thread you can put a breakpoint on the NSLog on the functions where you call the context as in the following piece of code and just use performSelectorOnMainThread on them.
if(![NSThread isMainThread]){
NSLog(#"Not the main thread...");
}
I hope that this may be helpful...
I had the same issue. If you run under the debugger and when the app "hangs" stop th app (use the "pause" button on the debugger. If you're at the executeFetchRequest line, then check the context variable. If it has a ivar _objectStoreLockCount and its greater than 1, then its waiting on a lock on the associated store.
Somewhere you're creating a race condition on your associated store.
This really sounds like trying to access a NSManagedObjectContext from a thread/queue other than the one that created it. As others suggested you need to look at your threading and make sure you are following Core Data's rules.
Executing fetch request must happen from the thread where context was created.
Remember it is not thread safe and trying to executeFetchRequest from another thread will cause unpredictable behavior.
In order to do this correctly, use
[context performBlock: ^{
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
}];
This will executeFetchRequest in the same thread as context, which may or may not be the main thread.
In my case the app would freeze before 'executeFetchRequest' without any warning. The solution was to wrap all db operations in #synchronized(persistentStore).
Eg:
NSArray *objects;
#synchronized([self persistentStoreCoordinator]) {
objects = [moc executeFetchRequest:request error:&error];
}
Delete all object with fetchrequest doesn't work for me, the sqlite looks corrupted. the only way I found is
//Erase the persistent store from coordinator and also file manager.
NSPersistentStore *store = [self.persistentStoreCoordinator.persistentStores lastObject];
NSError *error = nil;
NSURL *storeURL = store.URL;
[self.persistentStoreCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
//Make new persistent store for future saves (Taken From Above Answer)
if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}

Updates not saving to DB and properties not firing faults

Two hopefully minor questions regarding CoreData that I've been unable to find answers to:
1) I have a faulted object. Accessing an attribute as a property is not firing the fault, accessing the same property via KVC IS firing the fault. Any idea why?
i.e. object.title returns nil and object is still faulted, but [object valueForKey:#"title"] returns the title and the object is no longer a fault.
2) Updates to existing records have stopped working. Add/Delete works. Add/Update share the same code path (one is passed the existing object, the other a newly inserted object). However Update wont work. The data in the updated object is correct and set to the new values and the save succeeds with no errors, but the record in the database remains unchanged. Any idea?
NB: There is only one NSManagedObjectContext
Cheers
couldn't tell much from your description without code.
however it looks like you have updated the object in ram but the update wasn't submitted to the database layer making the physical change.
EDIT:
Yes, "Add" and "Delete" is different from "edit/update" a record.
for performance reason mapped objects are saved in memory as entities when you doing manipulation against NSManagedObjectContext you are not coding against database entirely.
check the link below:
http://cocoawithlove.com/2010/02/differences-between-core-data-and.html
normal work flow:
load appropriate rows from a database
instantiate objects from these rows
make changes to the graph objects
that are now in memory
commit the changes back to the
database
This is my core data for saving.
AppDelegate *app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
Tweet *newTweet = (Tweet *)[NSEntityDescription insertNewObjectForEntityForName:#"Tweet" inManagedObjectContext:app.managedObjectContext];
newTweet.status = status;
newTweet.post_date = theDate;
newTweet.post_id = post_id;
newTweet.sent_error = sent_error;
newTweet.sent_status = sent_status;
newTweet.screen_name = [Settings getActiveScreenName];
// SAVE
NSError* error = nil;
if (![app.managedObjectContext save:&error]) {NSLog(#"did this work?? = %# with userInfo = %#", error, [error userInfo]);}
I have this in my app delegate
- (void)applicationWillTerminate:(UIApplication *)application {
// need to check if TweetViewController is activel.
// User is writing a tweet.
UIViewController * topController = [navigationController visibleViewController];
if([topController isKindOfClass:[TweetViewController class]] ){
[Settings setObject:[(TweetViewController*)topController tweetText].text forKey:#"last_tweet_text"];
}
NSLog(#"good bye");
NSError *error;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Handle error.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
}
}
and this as well in AppDelegate
/**
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;
}
// ~/Library/Application Support/iPhone Simulator/User/
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"tweetv12.sqlite"]];
NSError *error;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
// Handle error
NSLog(#"cannot save data, change db name.");
}
return persistentStoreCoordinator;
}
I am also able to save delete and update data with this.