Core data won't save correctly - ios

I'm using a data model called settings which I setup in didLoad of my viewController:
settings = [NSEntityDescription insertNewObjectForEntityForName:#"Settings" inManagedObjectContext:[self managedObjectContext]];
Heres the managedobjectContext method:
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
When my stepper increments I want to update a string and then update the db.
- (IBAction)RowStepperAction:(UIStepper *)sender
{
double value = [sender value];
settings.numberofrows = [NSNumber numberWithDouble:value];
[self.RowNumber setText:[NSString stringWithFormat:#"%d", (int)value]];
NSError *error = nil;
// Save the object to persistent store
if (![[self managedObjectContext] save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
When I come to load the view again I do:
[self.ColumnStepper setValue:[settings.numberofcolumns doubleValue]];
[self.RowStepper setValue:[settings.numberofrows doubleValue]];
This returns the default values I set in the database. Why is this?

Every time you load the view again, you're creating a brand new settings object :
settings = [NSEntityDescription insertNewObjectForEntityForName:#"Settings" inManagedObjectContext:[self managedObjectContext]];
This will have your default values. You need instead to fetch your existing settings object, and only create a new one if that doesn't exist.
Your database will currently have several settings objects, one for each time you've loaded the view.

Related

Create relationship between 2 entities in different ViewControllers

i have 2 entities Called Playlists and Songs. First i'm passing the selected playlist into my singleton by using this code:
optionsSingle = [rowNumber singleObj];
optionsSingle.selectedRowNow = [devices objectAtIndex:indexPath.row];
the optionsSingle.selectedRowNow will return something like this, depending on name:
0xb922600 <x-coredata://053340C7-00A3-47EA-A213-4A9B6164504F/Playlists/p6> ; data: {
playlistName = playlist1;
songs = "<relationship fault: 0xb961480 'songs'>";
})
The problem is when i try to use this playlist object in the addSongsViewController it do not seem to work.
Im trying to include something like this to the songsDone method, but it wont let me use the addSongsObject. I've included the 2 entities to the .m file. The optionsSingle.selectedRowNumber is declared as as ´playlist´object type. How come i cant use this method on my playlist object that has been passed?
[optionsSingle.selectedRowNumber addSongsObject:newManagedObject2]
songsDone Method.
-(IBAction)songsDone:(id)sender{
AppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
Songs *newManagedObject2 = (Songs*)[NSEntityDescription insertNewObjectForEntityForName:#"Songs" inManagedObjectContext:context];
NSDate *today= [NSDate date];
[newManagedObject2 setValue:video.author forKey:#"author"];
[newManagedObject2 setValue:video.videoid forKey:#"link"];
[newManagedObject2 setValue:video.title forKey:#"songName"];
[newManagedObject2 setValue:today forKey:#"created"];
NSError *error = nil;
if (![_managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
(From my above comment:) If selectedRowNumber contains a Playlists object then you should declare it as such, and not as NSObject. Otherwise the compiler cannot "know" that it responds to addSongsObject:. - I.e. you should replace NSObject by Playlists in the definition of the selectedRowNumber property.

Core data save in Background with one-to-many relationship

in a core data app with a one-to-many relationship (one "test", many "measures"), I used to have this code :
In AppDelegate.m :
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil)
return _managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
In TableViewController.m :
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id contextDelegate = [[UIApplication sharedApplication] delegate];
if ([contextDelegate performSelector:#selector(managedObjectContext)])
context = [contextDelegate managedObjectContext];
return context;
}
- (void)saveEntryButton:(id)sender
{
NSManagedObjectContext *context = [self managedObjectContext];
if (self.test)
{
// Update existing test
self.test.number = self.numberTextField.text;
}
else // Create new test
{
self.test = [NSEntityDescription insertNewObjectForEntityForName:#"Test" inManagedObjectContext:context];
self.test.number = self.numberTextField.text;
}
if (isSaving)
{
NSManagedObjectContext *context = [test managedObjectContext];
self.measure = [NSEntityDescription insertNewObjectForEntityForName:#"Measure" inManagedObjectContext:context];
[test addWithMeasureObject:measure];
NSData *newDataArray = [NSKeyedArchiver archivedDataWithRootObject:plotDataArray];
self.measure.dataArray = newDataArray;
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error])
{
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
It works great, but of course, the [NSKeyedArchiver archivedDataWithRootObject:plotDataArray]; can take a few seconds and block the UI so I would like to do it in background.
I spent a few hours to read everything about the concurrency in core data (and I am quite new at it), but I didn't find anything regarding my problem : how to deal with a one-to-many relationship background save ?
What I've tried so far :
In AppDelegate.m
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil)
return _managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
//_managedObjectContext = [[NSManagedObjectContext alloc] init];
//[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
In TableViewController.m
- (void)saveEntryButton:(id)sender
{
NSManagedObjectContext *context = [self managedObjectContext];
if (self.test)
{
// Update existing test
self.test.number = self.numberTextField.text;
}
else // Create new test
{
self.test = [NSEntityDescription insertNewObjectForEntityForName:#"Test" inManagedObjectContext:context];
self.test.number = self.numberTextField.text;
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error])
{
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
if (isSaving)
{
NSManagedObjectContext *context = [test managedObjectContext];
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = context;
[temporaryContext performBlock:^{
self.measure = [NSEntityDescription insertNewObjectForEntityForName:#"Measure" inManagedObjectContext:temporaryContext];
[test addWithMeasureObject:measure];
NSData *newDataArray = [NSKeyedArchiver archivedDataWithRootObject:plotDataArray];
self.measure.dataArray = newDataArray;
// push to parent
NSError *error;
if (![temporaryContext save:&error])
{
// handle error
NSLog(#"error");
}
// save parent to disk asynchronously
[context performBlock:^{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSError *error;
if (![context save:&error])
{
// handle error
NSLog(#"error");
}
}];
}];
}
}
Of course, I receive a SIGABRT error as "test" and "measure" are not in the same context...I've tried a LOT of different things, but I'm really lost.
Thanks in advance for any help.
I see two questions here: background asynchronous saving and what to do with objects in different contexts.
First about saving. Are you sure that it is saving itself that blocks your UI thread and not call to archivedDataWithRootObject? If saving itself is relatively fast, you can consider calling only archivedDataWithRootObject on a background queue, and then communicating the results back to the main queue where you’ll do the save on your UI context.
If it is still the save that takes too long, you can use the approach for background asynchronous saving recommended by Apple. You need two contexts. One context – let’s call it background – is of private queue concurrency type. It is also configured with persistent store coordinator. Another context – let’s call it UI – is of main queue concurrency type. It is configured with background context as a parent.
When working with your user interface, you’re using the UI context. So all managed objects are inserted, modified, and deleted in this context. Then when you need to save you do:
NSError *error;
BOOL saved = [UIContext save:&error];
if (!saved) {
NSLog(#“Error saving UI context: %#“, error);
} else {
NSManagedObjectContext *parent = UIContext.parentContext;
[parent performBlock:^{
NSError *parentError;
BOOL parentSaved = [parent save:&parentError];
if (!parentSaved) {
NSLog(#“Error saving parent: %#“, parentError);
}
}];
}
The save of the UI context is very fast because it doesn’t write data to disk. It just pushes changes to its parent. And because parent is of private queue concurrency type and you do the save inside performBlock’s block, that save happens in background without blocking the main thread.
Now about different managed objects in different contexts from your example. As you discovered, you can’t set an object from one context to a property of an object in another context. You need to choose a context where you need to do the change. Then transfer NSManagedObjectID of one of the objects to the target context. Then create a managed object from ID using one of the context’s methods. And finally set this object to a property of another one.
Essentially you are on the right track, but missing a couple of key elements;
Firstly you will need to transfer test from your main context to the secondary - this is done in the following way;
//this is the object saved in your main managedObjectContext;
NSManagedObjectID *currentTest = test.objectID;
creating the secondary context for adding your related objects can be performed on a background thread. You can use and NSBlockOperation to do the secondary save and create the context at the same time.
here is a simple example using the standard person / address example wired to an IBAction
- (IBAction)button1Click:(id)sender {
NSError *saveError = nil;
// create instance of person to save in our primary context
Person *newParson = [[Person alloc]initIntoManagedObjectContext:self.mainContext];
newParson.name = #"Joe";
[self.mainContext save:&saveError];
//get the objectID of the Person saved in the main context
__block NSManagedObjectID *currentPersonid = newParson.objectID;
//we'll use an NSBlockOperation for the background processing and save
NSBlockOperation *addRelationships = [NSBlockOperation blockOperationWithBlock:^{
// create a second context
NSManagedObjectContext *secondContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[secondContext setPersistentStoreCoordinator:coordinator];
NSError *blockSaveError = nil;
/// find the person record in the second context
Person *differentContextPerson = (Person*)[secondContext objectWithID:currentPersonid];
Address *homeAddress = [[Address alloc]initIntoManagedObjectContext:secondContext];
homeAddress.address = #"2500 1st ave";
homeAddress.city = #"New York";
homeAddress.state = #"NY";
homeAddress.zipcode = #"12345";
Address *workAddress = [[Address alloc]initIntoManagedObjectContext:secondContext];
workAddress.address = #"100 home Ave";
workAddress.city = #"Newark";
homeAddress.state = #"NJ";
homeAddress.zipcode = #"45612";
[differentContextPerson addAddressObject:homeAddress];
[differentContextPerson addAddressObject:workAddress];
[secondContext save:&blockSaveError];
}];
[addRelationships start];
}
in the above initIntoManagedObjectContext is a simple helper method in the NSManagedObject subclass as follows;
- (id)initIntoManagedObjectContext:(NSManagedObjectContext *)context {
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Person" inManagedObjectContext:context];
self = [super initWithEntity:entity insertIntoManagedObjectContext:context];
return self;
}
An important note from Apple docs regarding NSBlockOperation:
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).

Saving the context does not persist an updated NSManagedObject

In my app I have 2 detail view controllers:
product name update controller
product properties update controller
In product properties update view controller everything is fine there is nothing wrong.
In product name update view controller however saving the context does not give any error. I see that the product name change in root view controller but when I re-open my app the product name shows me the old name. So it is not persisted.
What is my problem according to my updateProduct method:
-(void)updateProduct:(id)sender
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"Products" inManagedObjectContext:context]];
NSError *error = nil;
NSPredicate *predicateID =[NSPredicate predicateWithFormat:#"productID==%d",[secim intValue]];
[request setPredicate:predicateID];
NSArray *myobj=[context executeFetchRequest:request error:&error];
NSManagedObject *prod1=[myobj objectAtIndex:0];
[prod1 setValue:textProduct1.text forKey:#"productName"];
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self.navigationController popToRootViewControllerAnimated:YES];
NSLog(#"Data saved");
}
In addition to #Mundi here you are doing the following
NSArray *myobj = [context executeFetchRequest:request error:&error];
NSManagedObject *prod1 = [myobj objectAtIndex:0];
but you are not checking against error and neither if myobj contains elements.
ALWAYS check for errors whereas there is the possibility to have them.
Check with a breakpoint if your updateProduct method is called. I suspect it is not.
In the light of the other discussion, make sure that
the managed object context is not nil
prod1 (the managed object) is not nil
You can do this with breakpoints in the debugger or with log statements.

Core Data issue. Data won't save

So I have a utility app and I am trying to save some text into a "To" and "Message: text field on the Flipside View Controller. However, my data won't save. I am new to objective C and I have been using multiple different tutorials to the point where I have totally confused myself. Hopefully you can help me out. Not sure what else to do at this point...
FlipsideViewController.m
#import "CCCFlipsideViewController.h"
#import "CCCAppDelegate.h"
#import "CCCMainViewController.h"
#import "MessageDetails.h"
#interface CCCFlipsideViewController ()
{
// NSManagedObjectContext *context;
}
#end
#implementation CCCFlipsideViewController
#synthesize allMessageDetails;
#synthesize managedObjectContext;
- (void)awakeFromNib
{
[super awakeFromNib];
CCCAppDelegate *appDelegateController = [[CCCAppDelegate alloc]init];
self.managedObjectContext = appDelegateController.managedObjectContext;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"MessageDetails" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.allMessageDetails = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
/*
NSManagedObject *managedObject; = [_fetchedResultsController valueForKey:#"to"];
self.toTextField.text = managedObject to;
messageDetails.to = [allMessageDetails firstObject];
self.toTextField.text = messageDetails.to;
messageDetails.message = [allMessageDetails valueForKey:#"message"];
self.messageTextField.text = messageDetails.message;
*/
NSLog(#"The 'to' is currently at %# after viewdidload", self.toTextField.text);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [textField resignFirstResponder]; //function says that if (bool) the text field is open and the keyboard hits return, text field is to resign first responder.
}
#pragma mark - Actions
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];
}
- (IBAction)resignFirstResponder:(id)sender {
[self.toTextField resignFirstResponder];
[self.messageTextField resignFirstResponder];
NSLog(#"Resigned First Responder");
}
- (IBAction)save:(id)sender {
// Create a new instance of the entity managed by the fetched results controller.
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
[newManagedObject setValue:self.toTextField.text forKey:#"to"];
[newManagedObject setValue:self.messageTextField.text forKey:#"message"];
// Save the context.
NSError *error = nil;
if (![context 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 Fetched results controller
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MessageDetails" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"to" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![_fetchedResultsController performFetch:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 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();
}
return _fetchedResultsController;
}
#end
I didn't look at all your code because there was a problem near the top that negates everything you do thereafter. Don't alloc/init your app delegate in awakeFromNib or anywhere else for that matter. The one and only instance of your app delegate already exists (I have no idea what happens when there is more than one app delegate).
CCCFlipsideViewController needs to gain access to the managed object context through another means. Perhaps CCCMainViewController (or another view controller) could set the CCCFlipsideViewController's managedObjectContext property. If CCCMainViewController does not have access to the managed object context, have the app delegate pass that context to it.
Example:
App delegate sets a managedObjectContext property on the root view controller; the root view controller, in turn, sets the managedObjectContext property on a child view controller (like your flipside VC), etc.
You don't seem to ever actually set self.messageTextField.text or self.toTextField.text to anything -- you have commented out code in your viewDidLoad method which sets these fields. bilobatum is entirely correct about your AppDelegate issue as well -- you could also use something like
[((NSObject*)[UIApplication sharedApplication].delegate) valueForKey: #"managedObjectContext"];
to get the app delegate for your application if you want to fix that fast, though long term bilobatum's solution to this is better design.
Honestly, I think you've done quite a number on this code... ;)
OK, first off, in your save method, don't create another NSManagedObjectContext, use the instance variable you already declared, "managedObjectContext."
Secondly, I think you've made things way too complicated for yourself... Storing Core Data is actually shockingly simple once you've created the NSManagedObject subclasses and set up everything in the App Delegate...
It seems as if you wouldn't need any info from the "fetchedResultsController" at that point in your code, since you're saving, not fetching. Maybe try changing your save method to something like:
- (IBAction)save:(id)sender {
NSEntityDescription *entity = [NSEntityDescription insertNewObjectForEntityForName:#"MessageDetails" inManagedObjectContext:self.managedObjectContext];
// If appropriate, configure the new managed object.
[entity setValue:self.toTextField.text forKey:#"to"];
[entity setValue:self.messageTextField.text forKey:#"message"];
// Save the context.
NSError *error = nil;
[self.managedObjectContext save:&error]
if (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();
}
}
Edit: And to get the managed object context from the app delegate...
Right after your #synthesize's, create a variable for the App Delegate.
AppDelegate* appDelegateController;
And in viewDidLoad, initialize it:
appDelegateController = (AppDelegate*)[[UIApplication sharedApplication] delegate];
Right after viewDidLoad (or anywhere you want), you can stick in a method to declare the managed object context:
- (NSManagedObjectContext*)managedObjectContext {
return appDelegateController.managedObjectContext;
}
Then back in viewDidLoad, call that method with:
self.managedObjectContext = [self managedObjectContext];

NSmanaged context threads

I use a singleton for working with arrays etc. cross the views in the application.
To initialize the singleton and the NSManagedObjectContext, so that I can fetch objects, I use:
+(DataControllerSingleton *)singleDataController
{
static DataControllerSingleton * single=nil;
#synchronized(self)
{
if(!single)
{
single = [[DataControllerSingleton alloc] init];
NSManagedObjectContext *context = [single.fetchedResultsController managedObjectContext];
single.masterCareList = [[NSMutableArray alloc] init];
}
}
return single;
}
When I insert a new object that object will not show up in display functions until I restart the application. I insert new object through this method in the singleton class:
- (void)insertNewObject:(Care *)care
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:
[entity name] inManagedObjectContext:self.managedObjectContext];
NSString *fileName = care.pictureURL;
NSString *text = care.causeText;
NSDate *date = care.date;
NSData *imgData = care.imageData;
[newManagedObject setValue:fileName forKey:#"urlPath"];
[newManagedObject setValue:text forKey:#"name"];
[newManagedObject setValue:date forKey:#"date"];
[newManagedObject setValue:imgData forKey:#"imageData"];
// Save the context.
[self saveContext];
NSError *error = nil;
if (![context 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();
}
}
My count method is the way I can tell that the new object is not included until I restart the application. The count method is also in the singleton as well.
- (NSUInteger)countOfList
{
NSArray *fetchedData = [_fetchedResultsController fetchedObjects];
return [fetchedData count];
}
When calling singleton I use:
DataControllerSingleton *singletonData = [DataControllerSingleton singleDataController];
[singletonData insertNewObject:care];
managedObjectContext property:
.h:
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
.m:
#implementation DataControllerSingleton
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
Why will not my new object show up in ex count until I restart application?
Am I somehow using different threads with different contexts, or different fethedResultsController or different singleton (shouldnt be possible right?)??
I added these two lines, which are not included in the genereated CoreData Stack, and it now works fine.
In singleton header:
#interface DataControllerSingleton : NSObject <NSFetchedResultsControllerDelegate>
In implementation file,
(NSFetchedResultsController *)fetchedResultsController {
_fetchedResultsController.delegate = self;
As I understand from your question, you are using a table or similar.
If you want to update the table as soon as you save the context you need to:
Reload the data table [table reloadData];
or implement in the correct delegate methods of (take a look to How To Use NSFetchedResultsController)
If you follow the first option, you can just do a save in the context and call realod data on the table.
NSError *error = nil;
if (![context 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();
}
[table reloadData];
NOTE THAT YOU ARE CALLING THE SAVE TWICE Do it once. In this case I suppose that [self saveContext]; does the saving as above.
If you follow the second approach, the data reload woul be handled for you.
Hope that helps.
Edit
The delegate of your fetched results controller should be a view controller (the one that contains the table). Do not put it in your singleton!!

Resources