0

When I try to save data for private NSManagedObjectContext I get deadlock even if operations for this context are called inside performBlock: block. This is strange because this block should be performed asynchronosuly withouth interrupting the main UI/UX thread.
Here is the code of this method:

- (void)loadTimetableToCoreData:(id)timetable
{   
    // Initializing temporary context
    NSManagedObjectContext *tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tempContext.parentContext = self.moc;

    [tempContext performBlock:^{
      // Here is the parsing 

        NSLog(@"Finished loading to temp MOC");

        NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Timetable"];
        [r setIncludesPendingChanges:NO];
        NSArray *existingTimetables = [tempContext executeFetchRequest:r error:nil];

        for (Timetable *table in existingTimetables) {
            [tempContext deleteObject:table];
        }

        // Saving procedure with multithreading
        NSError *error;
        if (![tempContext save:&error]) {
            NSLog(@"Couldn't save: %@", [error localizedDescription]);
        }

        NSLog(@"Finished saving to temp MOC");

        [self.moc performBlock:^{
            // Save groups to presistant store
            NSError *error;
            if (![self.moc save:&error]) {
                NSLog(@"Couldn't save: %@", [error localizedDescription]);
            }
            NSLog(@"Finished saving to main MOC");

            [self.writer performBlock:^{
                // Save groups to presistant store
                NSError *error;
                if (![self.writer save:&error]) {
                    NSLog(@"Couldn't save: %@", [error localizedDescription]);
                }
                NSLog(@"Finished saving to writer MOC");
            }];
        }];
    }];
}

As you can see there are some NSLogs inside this method and to visualize my problem I get stuck between Finished loading to temp MOC and Finished saving to temp MOC.
What am I doing wrong and how to unlock the main thread?

Update

Here is the screen from Instruments and what I can see... The controllerDidChangeCintent is killing everything. enter image description here I know that this is caused by those lines from loadTimetableToCoreData:

NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Timetable"];
        [r setIncludesPendingChanges:NO];
        NSArray *existingTimetables = [tempContext executeFetchRequest:r error:nil];

        for (Timetable *table in existingTimetables) {
            [tempContext deleteObject:table];
        }

But I can't get rid of them! Or I don't know how....

cojoj
  • 6,405
  • 4
  • 30
  • 52
  • 1
    where do you get stuck? , can you step through? – Warren Burton Apr 09 '14 at 15:24
  • If you pause the app while inside your block, what does the main thread's stack look like? – Phillip Mills Apr 09 '14 at 15:27
  • @PhillipMills Which one is the main thread's stack when I stop at breakpoint? – cojoj Apr 09 '14 at 15:36
  • In the Debug Navigator it should say "Thread 1, Queue: com.apple.main-thread". (There's a slider at the bottom that can be adjusted to show all the frames.) – Phillip Mills Apr 09 '14 at 16:12
  • Maybe your nested blocks are the problem? See also here: http://stackoverflow.com/questions/11786436/core-data-nested-managed-object-contexts-and-frequent-deadlocks-freezes and here: http://stackoverflow.com/questions/11899875/core-data-multithread-store-relations/11900484#11900484 – koen Apr 09 '14 at 17:06
  • How and when are you calling `loadTimetableToCoreData:` and what is the relationship between `self.moc` and `self.writer`? – Jody Hagins Apr 09 '14 at 17:31
  • @JodyHagins I call `loadTimetableToCoreData:` when user **pull-to-refresh**. And relationship is `self.moc.parnet = self.writer`. – cojoj Apr 09 '14 at 17:35
  • You have a FRC installed on self.moc... it watches for changes... when you do the fetch in the temporary context, it pulls data into the parent context, which sees those changes, and tries to do something else... possibly another fetch... but the first one is not done yet... at least that's what it looks like... I am making a lot of assumptions about the rest of your code... – Jody Hagins Apr 09 '14 at 17:52
  • How many records are you deleting? – Dan Shelly Apr 09 '14 at 18:09
  • @DanShelly There is only one Timetable but it has relationships with other entities and delete rules are set to cascade... So Timetable has 150 activities and for each activity a tutor, group and location... So I gues it'll be maximum amount of 250 records. So it's not a big amount but is blocking main thread for c.a 4 sec – cojoj Apr 09 '14 at 18:19
  • Try deleting a `Timetable` with no relations and check if there's any change in performance. my guess is that the deletion reported to the main context is triggering a cascade of faults for each deleted object (you could keep drilling down in instruments to see what is the cause for the holdup). – Dan Shelly Apr 09 '14 at 18:36
  • @DanShelly when I've switched from `NSFetchedResultsController` delegate methods to simple `[tableView reloadData]` it's working like it should! – cojoj Apr 09 '14 at 18:40

0 Answers0