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
}
Related
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:
I want to reset the data store clean by removing the app's sqlite file. I wrote this function in my data helper class:
-(void) resetPersistenStore {
NSError *error = nil;
[persistentStoreCoordinator_ release];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MyApp.sqlite"];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
if (error) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
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();
}
managedObjectModel_ = nil;
}
I put this following test in UIApplication::didFinishLaunchingWithOptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* test */
[TestDataHelper populateTestData:[self managedObjectContext]];
[TestDataHelper populateTestData:[self managedObjectContext]];
[self resetPersistenStore];
[TestDataHelper populateTestData:[self managedObjectContext]];
[TestDataHelper testPopulateTestData:[self managedObjectContext]];
Instead of one set of data created by the function populateTestData, I can see actually three set of data (because I called the function three times)
It is clear that resetPersistenStore() works, because without it, the data will keep accumulating.
So my question is:
Why the reset does not take effect immediately?
I have set managedObjectContext to nil in the reset function, but it did not help.
Here is my populateTestData function
+(void)populateTestData:(NSManagedObjectContext*)managedObjectContext {
Stock* s1 = (Stock*)[NSEntityDescription insertNewObjectForEntityForName:#"Stock"
inManagedObjectContext:managedObjectContext];
s1.code = #"ABC2";
s1.name = #"ABC";
s1.enteredBy = #"akong";
[managedObjectContext save:&error];
if (error) {
NSLog(#"Data error %#", [error description]);
} else {
NSLog(#"Init completed");
}
}
Even though the context saved the data in populateTestData, it still has data loaded in it.
Suppose when the application starts, the file has 3 objects. Now the first populateTestData message adds an object into the context, and save it. So 4 objects in the file, 1 in the context. After the second message, 5 in the file, 2 in the context. Now the file is gone, but still there are 2 in the context. Now the final message adds another object to the context and to the file, so there are 3 objects.
You said setting managedObjectContext to nil in the reset function didn't help. I doubt if the context has been properly reset there. Try [managedObjectContext reset] instead.
I am only speculating here but are you by any chance using a fetchedResultsController to verify/display the results of these operations? If so try to set its caching to nil and see if it helps.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"xxxxxxxx" cacheName:nil];
Cheers,
Rog
It may simply be an artifact of the simulator. If you're running in the simulator, you may need to reset it. From the iOS Simulator menu, select Reset Content and Settings...
I have been working with Core Data in an iPad app and I can successfully save and fetch data inside the app. However when completely closing the application, fully, quit, take it out of multitasking, and that data disappears.
So does Core Data in anyway keep this data anywhere when the app is closed? Or do I need to look somewhere else?
EDIT: This is in the app delegate didFinishLaunchingWithOptions: [[[UIApplication sharedApplication] delegate] managedObjectContext]; and then I have this: context_ = [(prototypeAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; in the UIView subclass.
This is the NSPersistentStoreCoordinator code premade in the app delegate:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"prototype.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_;
}
So far I am using this to fetch data:
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *testEntity = [NSEntityDescription entityForName:#"DatedText" inManagedObjectContext:context_];
[fetch setEntity:testEntity];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"dateSaved == %#", datePicker.date];
[fetch setPredicate:pred];
NSError *fetchError = nil;
NSArray *fetchedObjs = [context_ executeFetchRequest:fetch error:&fetchError];
if (fetchError != nil) {
NSLog(#"fetchError = %#, details = %#",fetchError,fetchError.userInfo);
}
noteTextView.text = [[fetchedObjs objectAtIndex:0] valueForKey:#"savedText"];
And this to save data:
NSManagedObject *newDatedText;
newDatedText = [NSEntityDescription insertNewObjectForEntityForName:#"DatedText" inManagedObjectContext:context_];
[newDatedText setValue:noteTextView.text forKey:#"savedText"];
[newDatedText setValue:datePicker.date forKey:#"dateSaved"];
NSError *saveError = nil;
[context_ save:&saveError];
if (saveError != nil) {
NSLog(#"[%# saveContext] Error saving context: Error = %#, details = %#",[self class], saveError,saveError.userInfo);
}
Do you save the context in the right places? It is a common mistake not to save the context when entering background application state only in willTerminate.
Save the context in the following appdelegate method:
-(void)applicationDidEnterBackground:(UIApplication *)application
You are saving your context directly after inserting the object, this should be sufficient. Check the sqlite file in simulator if it contains any data after saving.
if
noteTextView.text = [[fetchedObjs objectAtIndex:0] valueForKey:#"savedText"];
does not throw an exception, there is an object found in context. Maybe it does not contain the expected value?
Log the returned object from your fetchrequest to console to see if this might be the case
You should post the code that sets up your NSPersistentStoreCoordinator and adds your NSPersistentStore. By any chance are you using NSInMemoryStoreType as the type of your store? Because that would result in the behavior you're seeing. Alternately, you could be using a different path to the store each time, which would give you a fresh store each time. In general, your store should be in your Documents folder, and it should be given the same name on every launch. It should also use the NSSQLiteStoreType
I have discovered the problem. It turns out that due to its use of UIDatePicker, at the start of the program it set that date picker to today using:
NSDate *now = [[NSDate alloc] init];
[datePicker setDate:now];
So without using this it works perfectly. So currently I am looking for a solution to this issue, as this line seems to cause the problem.
UIDatePicker Interfering with CoreData
If you add a CoreData after create your project.There is a risk to make mistake in lazy_init your NSManagedObject.
-(NSManagedObjectContext*) managedObjectContext{
if (!_managedObjectContext) {
_managedObjectContext =[self createManageObjectContextWithName:#"name.sqlite"];
}
return _managedObjectContext;}
Here is the right way:
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;}
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.
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?