Deleted object being returned in a Core Data fetch

Asked

Viewed 51 times

0

I have a "small" problem when using Core Data.

This is my architecture:

Synchronizer -> Syncservice -> Persistenceservice -> Nsmanagedobject

All classes in the Persistenceservice layer inherit this structure:

# PersistenceService.h
#import <Foundation/Foundation.h>

@interface PersistenceService : NSObject

@property (nonatomic, retain) NSManagedObjectContext *context;

-(instancetype) init;
-(void) saveContext;
@end

# PersistenceService.m
@implementation PersistenceService

-(instancetype) init {
    self = [super init];

    if (self) {
        self.context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        self.context.parentContext = [DataManager sharedInstance].managedObjectContext;
    }

    return self;
}

-(void) saveContext {
    NSManagedObjectContext *context = self.context.parentContext;

    [self.context performBlock:^{

        NSError *error;
        [self.context save:&error];

        [context performBlock:^{
            NSError *error;
            [context save:&error];

            [context.parentContext performBlock:^{
                NSError *error;
                [context.parentContext save:&error];

            }];
        }];
    }];

}

@end

At the beginning of the execution cycle, my Synchronizer does a fetch of the objects I will need and step for Syncservice to operate on them. I always use the parentContext for anything other than changing (creating, editing, saving, deleting) the objects themselves:

# Synchronizer.m
-(void) synchronize {
    NSArray *pseudoLeads = [[[PseudoLeadPersistenceService alloc] init] getAllParentPseudoLeads];
    if (pseudoLeads) {
        PseudoLeadDAO *pseudoLead = [pseudoLeads objectAtIndex:0];
        if ([pseudoLead.type isEqualToNumber:[NSNumber numberWithInt:Capture]]) {
            CaptureSyncService *service = [[CaptureSyncService alloc] initWithDelegate:self andPseudoLead:pseudoLead];
            [service executeRequest];
        } else {
            HotleadSyncService *service = [[HotleadSyncService alloc] initWithDelegate:self andPseudoLead:pseudoLead];
            [service executeRequest];
        }
    }
}

After Syncservice has finished performing its operations, I need to delete the object so that it exits the queue and the next ones are handled. Below follows the code I use to recover the object I wish to delete on context normal and where I actually delete:

# PseudoLeadPersistenceService.m
-(void) deletePseudoLeadById:(NSNumber *)pseudoLeadId andEventId:(NSNumber *)eventId {
    PseudoLeadDAO *pseudoLeadDAO = [PseudoLeadDAO findPseudoLeadById:pseudoLeadId andEventId:eventId inContext:self.context];
    [self.context deleteObject:pseudoLeadDAO];
    [self saveContext];
}

After that the process starts again in Synchronizer (or should). The problem is that when returning to the method -(void) synchronize and fetch, the object that has just been deleted is being returned again. No matter how many fetchs I do at this point, it always comes. The process continues and only stops when the object arrives again in the deletion method, which is when trying to access the properties of the nil object is returned and causes the program to break.

1 answer

1


The problem was the competition. The thread created to save the contexts was not finishing before the next fetch.

I solved the problem by adding the following method to Persistenceservice.

# PersistenceService.m
-(void) saveContextAndWait {
    NSManagedObjectContext *context = self.context.parentContext;

    [self.context performBlockAndWait:^{

        NSError *error;
        [self.context save:&error];

        [context performBlockAndWait:^{
            NSError *error;
            [context save:&error];

            [context.parentContext performBlockAndWait:^{
                NSError *error;
                [context.parentContext save:&error];

            }];
        }];
    }];
}

Now the method that deletes the object calls this new:

# PseudoLeadPersistenceService.m
-(void) deletePseudoLeadById:(NSNumber *)pseudoLeadId andEventId:(NSNumber *)eventId {
    PseudoLeadDAO *pseudoLeadDAO = [PseudoLeadDAO findPseudoLeadById:pseudoLeadId andEventId:eventId inContext:self.context];
    [self.context deleteObject:pseudoLeadDAO];
    [self saveContextAndWait];
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.