Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7979085
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 4, 20262026-06-04T09:40:34+00:00 2026-06-04T09:40:34+00:00

Insert ( NSFetchedResultsChangeInsert )is working from my background thread, from that same thread, using

  • 0

Insert (NSFetchedResultsChangeInsert)is working from my background thread, from that same thread, using the same managedObjectContext save-merge notification and thus does get saved correctly, delete is not working (visible delete animation in tableviews thus not working).

Updated, now showing all my code for the problematic SchedulesViewController.m:

#import "SchedulesViewController.h"
#import "CustomScheduleTableViewCell.h"
#import <QuartzCore/QuartzCore.h>
#import "ViewScheduleViewController.h"

@implementation SchedulesViewController {
    NSIndexPath *deleteActionIndexPath;
}

@synthesize fetchedResultsController, managedObjectContext;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (managedObjectContext == nil) { 
        managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
    }

    self.title = @"Schema's";

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    NSError *error = nil;
    if (![[self 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();
    }
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    //storedReminderSchedules = nil;
    //context = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSLog(@"Schedules viewWillAppear");
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [[fetchedResultsController sections] count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    // check if we really have any sections in the managed object:
    //if (!fetchedResultsController.sections.count) return @"Persoonlijk";

    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo name];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // check if we really have any sections in the managed object:
    //if (!fetchedResultsController.sections.count) return 0;

    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ScheduleCell";
    CustomScheduleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}


// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)configureCell:(CustomScheduleTableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath {
    // Configure the cell.
    ReminderSchedule *reminderSchedule = [fetchedResultsController objectAtIndexPath:indexPath];
    cell.name.text = reminderSchedule.name;
}

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([[[[fetchedResultsController sections] objectAtIndex:indexPath.section] name] hasPrefix:@"Dr."]) {
        ViewScheduleViewController *controller = [[ViewScheduleViewController alloc]init];
        controller.reminderSchedule = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
        controller.context = [fetchedResultsController managedObjectContext];
        [self.navigationController pushViewController:controller animated:YES];
    }
    else {
        [self performSegueWithIdentifier:@"EditSchedule" sender:self];
    }
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewCellEditingStyleDelete;
}

#pragma mark - ModifyScheduleViewControllerDelegate
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"AddSchedule"])
    {
        [TestFlight passCheckpoint:@"Add Schedule"];
        // Get reference to the destination view controller
        UINavigationController *navigationController = segue.destinationViewController;
        ModifyScheduleViewController *controller = [[navigationController viewControllers] objectAtIndex:0];
        controller.delegate = self;
        controller.fetchedResultsController = self.fetchedResultsController;
        [controller.navigationItem.rightBarButtonItem setEnabled:NO];
    }
    else if ([segue.identifier isEqualToString:@"EditSchedule"]) {
        [TestFlight passCheckpoint:@"Edit Schedule"];
        // Get reference to the destination view controller
        UINavigationController *navigationController = segue.destinationViewController;
        ModifyScheduleViewController *controller = [[navigationController viewControllers] objectAtIndex:0];
        controller.delegate = self;
        controller.fetchedResultsController = self.fetchedResultsController;
        controller.reminderSchedule = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
    } 
}

#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:@"ReminderSchedule" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptorName = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    NSSortDescriptor *sortDescriptorSection = [[NSSortDescriptor alloc] initWithKey:@"sectionName" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptorSection,sortDescriptorName, 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:managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    return fetchedResultsController;
}    

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    NSLog(@"didChangeSection");
    switch(type) {
        case NSFetchedResultsChangeUpdate: 
            [self.tableView reloadData]; 
            break;
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


// Notifies the delegate that section and object changes are about to be processed and notifications will be sent. 
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
       atIndexPath:(NSIndexPath *)indexPath 
     forChangeType:(NSFetchedResultsChangeType)type 
      newIndexPath:(NSIndexPath *)newIndexPath {

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView  insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                                   withRowAnimation:UITableViewRowAnimationFade]; 
            break;
        case NSFetchedResultsChangeUpdate:
            [self configureCell:(CustomScheduleTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]
                    atIndexPath:indexPath];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView  deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                                   withRowAnimation:UITableViewRowAnimationFade]; 
            break;
        case NSFetchedResultsChangeMove:
            [self.tableView  deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                                   withRowAnimation:UITableViewRowAnimationFade]; 
            [self.tableView  insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
                                   withRowAnimation:UITableViewRowAnimationFade]; 
            break;      
        default:
            break;
    }   
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
} 

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
    [self.tableView reloadData];
}

@end

Update
Extra info:

Inserting and deletion of objects happens from the same thread, they use the same managedObjectContext and use the same save store. In fact, first objects are inserted then others are deleted then there is one save.

I’m saving using NSManagedObjectContextDidSaveNotification that triggers the save merge in AppDelegate.

Update
More code:

AppDelegate.m

- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}

-(void)mergeChanges:(NSNotification *)saveNotification {
    NSLog(@"Merging and saving");
    if ([NSThread isMainThread])
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
    else
        [self performSelectorOnMainThread:@selector(mergeChanges:) withObject:saveNotification waitUntilDone:NO];
}

BacgroundThread.m

AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];

NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
[newMoc setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];

//Shortened insert section for illustration (insertion works good)

ReminderSchedule *reminderSchedule = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:newMoc];

//Actual delete section code

if ([jsonDict objectForKey:@"deletedSchedules"] != nil) {
    NSArray *deletedSchedules = [jsonDict objectForKey:@"deletedSchedules"];

    for (int i = 0; i < [deletedSchedules count]; i++) {
        NSInteger externalScheduleID = [[deletedSchedules objectAtIndex:i] intValue];

        NSLog(@"Removing schedule %d", externalScheduleID);

        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"ReminderSchedule" inManagedObjectContext:newMoc];
        [fetchRequest setEntity:entity];

        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"externalScheduleID == %d", externalScheduleID];
        [fetchRequest setPredicate:predicate];

        NSError *error = nil;
        NSArray *result = [newMoc executeFetchRequest:fetchRequest error:&error];

        for (NSManagedObject *managedObject in result) {
            [newMoc deleteObject:managedObject];
        }
    }
}

//Save after insert and delete

NSError *saveError = nil;
if (![newMoc save:&saveError]) {
    NSLog(@"Whoops, couldn't save: %@", [saveError localizedDescription]);
} 


[[NSNotificationCenter defaultCenter] removeObserver:theDelegate];        

Update
Doing an insert and delete and then save works. Doing insert by itself works. Doing delete by itself does not worK.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-04T09:40:35+00:00Added an answer on June 4, 2026 at 9:40 am

    Make sure NSNotificationCenter allways gets registered with NSManagedObjectContextDidSaveNotification, not only when there is something to insert.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

string.insert in c# doesn't overwrite the character that is in the startindex does it?
INSERT INTO [Tasks] ([LoginName] ,[Type] ,[Filter] ,[Dictionary] ,[Description]) Select N'Anonymous',4,'SomeTable.targetcode in (select Code from
INSERT INTO geo (city, country, latitude, longitude) SELECT ansiname, country_code, latitude, longitude FROM geonames2
My insert and update pages (through my admin forlder) into mysql stopped working. When
INSERT IGNORE INTO `PREFIX_tab_lang` (`id_tab`, `id_lang`, `name`) (SELECT `id_tab`, id_lang, (SELECT tl.`name` FROM `PREFIX_tab_lang`
insert ignore into table1 select 'value1',value2 from table2 where table2.type = 'ok' When I
INSERT INTO product_search_table (id, score) VALUES ( SELECT product_id, 50 FROM cart_product WHERE product_id
insert into test.qvalues select * from qcvalues.qvalues; i would like to knwo if the
INSERT IGNORE INTO table3 (id1, id2) VALUES SELECT id1, id2 FROM table1, table2; What's
INSERT INTO tblPubInfo i (img_name) SELECT f.img_name FROM tblPubFiles f WHERE f.img_name<>'' AND f.pub_uid

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.