EXC_BAD_ACCESS (SIGSEGV) when using deleteObject: in the master data store

In my application, I delete (or try to delete) all records from the two main data stores before adding new ones. These are 2 simple repositories containing data related to entries in the address book (VIContacts contains the contact identifier and the vcard hash code (integer), VIGroup contains the group identifier and group name).

To remove all contacts from the store, I use this piece of code in the method -clear::


NSArray *allOldRowsInVIContacts = [[mainContext fetchObjectsForEntityName:[VIContact name]
                                               includePropertyValues:NO
                                               withPredicate:nil] copy];

for (NSManagedObject *obj in allOldRowsInVIContacts) {
    @try {
        [mainContext deleteObject:obj];
    }
    @catch (NSException *exception) {
        NSLog(@"Exception Triggered: %@", exception.reason);
        [NSException raise:exception.reason format:@"thrown on vicontacts."];
    }
}

[allOldRowsInVIContacts release];

if (![mainContext save:error]) {
    return NO;
}

NSArray *allOldRowsInVIGroups = [[mainContext fetchObjectsForEntityName:[VIGroup name]
                                                 includePropertyValues:NO
                                                         withPredicate:nil] copy];

NSLog(@"all rows in VIGroups count: %d", [allOldRowsInVIGroups count]);

for (NSManagedObject *obj in allOldRowsInVIGroups) {
    @try {
        [mainContext deleteObject:obj];
    }
    @catch (NSException *exception) {
        NSLog(@"Exception Triggered: %@", exception.reason);
        [NSException raise:exception.reason format:@"thrown on vigroups."];
    }
}

[allOldRowsInVIGroups release];

NSLog(@"at the end of -clear: Going to save context.");

/* SAVE */
if (![mainContext save:error]) {
    return NO;
}

An application always looks like a crash around the VIGroup area.

The crash log is as follows:


Crashed Thread:  5  Dispatch queue: com.apple.root.default-priority

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
...
Thread 5 Crashed:: Dispatch queue: com.apple.root.default-priority
0   com.apple.CoreFoundation        0x00007fff82532574 __CFBasicHashRehash + 1412
1   com.apple.CoreFoundation        0x00007fff8252b41b __CFBasicHashAddValue + 75
2   com.apple.CoreFoundation        0x00007fff82531f78 CFBasicHashAddValue + 3176
3   com.apple.CoreFoundation        0x00007fff82547899 CFSetAddValue + 121
4   com.apple.CoreData              0x00007fff8520e3dc -[NSManagedObjectContext deleteObject:] + 220
5   com.andrei.AddressBookApp       0x000000010004da9a -[AddressBookFrameworkSyncHelper clear:] + 490
6   com.andrei.AddressBookApp       0x000000010004c8f9 +[AddressBookFrameworkSyncHelper saveSnapshot:] + 105
7   com.andrei.AddressBookApp       0x000000010002d417 -[SLSyncOperation main] + 2631
8   com.apple.Foundation            0x00007fff8b68dbb6 -[__NSOperationInternal start] + 684

Other information

I used tools to find zombies, but no one appeared. There are some leaks in the application, but none of them are related to master data.

VIGroup VIContact . .

, @catch, Exception triggered: ... .

. , Mountain Lion Snow Leopard.

. .

MOC :

"NSOperation" ( "SLSyncOperation" ) "NSOperationQueue". SLSyncOperation NSOperationQueue:


[backgroundQueue setMaxConcurrentOperationCount:1];

// has a custom initializer
currentOperation = [[SLSyncOperation alloc] initWithPersistentStoreCoordinator:persistentStoreCoordinator
                                                                   andDelegate:delegate
                                                               forceRemoteSync:forceSync];

[backgroundQueue addOperation:currentOperation];

main SLSyncOperation ( NSOperation):


- (void)main {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    syncProgressTracker = [SLSyncProgressTracker sharedProgressTracker];
    syncProgressTracker.currentStatus = SLSyncStatusIdle;

    // ... some other setup and sending notifications ...

    /* Set up. */
    managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    managedObjectContext = [[NSManagedObjectContext alloc] init];

    // persistentStoreCoordinator is passed from the app delegate
    [managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];

    // ... continues with other logic (syncing to a server), and the end of the method is: ...

    /* Tear down. */
    [managedObjectContext release];
    managedObjectModel = nil;

    [pool drain];
}

MOC:

MOC , , SLSyncOperation. , ...? , .

MOC :


+ (AddressBookFrameworkSyncHelper *)sharedHelper {
    if (!_sharedAddressBookHelper) {
        _sharedAddressBookHelper = [[AddressBookFrameworkSyncHelper alloc] init];
    }

    return _sharedAddressBookHelper;
}

- (id)init {
    if (self = [super init]) {        
        mainContext = [(AddressBookAppAppDelegate *)[[NSApplication sharedApplication] delegate] managedObjectContext];
        addressBookRef = [ABAddressBook sharedAddressBook];

        // disable undo manager - uses less memory
        [mainContext setUndoManager:nil];        
    }

    return self;
}

MOC (mainContext) , , ..


//saving
[sharedABF.mainContext save:error];

// passing it to a Core Data method
VIContact *contactToAdd = [VIContact newOrExistingContactWithID:contactID
                                                      inContext:sharedABF.mainContext
                                                          error:error];

// that method looks like this
+ (VIContact *)newOrExistingContactWithID:(NSString *)contactID inContext:(NSManagedObjectContext *)context error:(NSError **)error {    
    VIContact *theContact = [[context fetchObjectsForEntityName:[VIContact name]
                                          includePropertyValues:YES
                                                  withPredicate:
                              @"personID == %@", contactID] lastObject];

    if (theContact) {
        return [theContact retain];
    } else {
        // no contact found with that ID, return a new one
        VIContact *newContact = [[VIContact alloc] initAndInsertInContext:context];
        newContact.personID = contactID;
        return newContact;
    }
}

// and then fetch all rows in a Core Data entity and remove them
NSArray *allOldRowsInVIContacts = [mainContext fetchObjectsForEntityName:[VIContact name]
                                                   includePropertyValues:NO
                                                           withPredicate:nil];

for (NSManagedObject *obj in allOldRowsInVIContacts) {
    [mainContext deleteObject:obj];
}

if (![mainContext save:error]) {
    return NO;
}

fetchObjectsForEntityName .

, , . , , MOC.

, mainContext SLSyncOperationThread.Name set.. , , NSLog, . . , . , , .

+5
3

-, , , ?

-, , NULL .

-, NSManagedObjectContext ?

, clear NSOperationQueue, . MOC .

( ) , MOC , .

, , . , NSSet, NSArray... , , , .

, , clear. , , :

// ... continues with other logic (syncing to a server), and the end of the method is: ...

, , , mainContext MOC . SLSyncOperation MOC (, ). saveSnapshot, clear, , , mainContext, MOC, NSOperation.

mainContext - MOC, AppDelegate, . "" . . . № 1 . MOC.

, , - , MOC . . , - , mainContext ( saveSnapshot main.

:

loocally generated MOC , MOC. , MOC?

mainContext MOC, , . perform GCD.

dispatch_async(dispatch_get_main_queue(), ^{
    // Now you can call the saveSnapshot and other stuff that must use
    // mainContext since stuff in this block will execute on the main thread.
});

MOC - , concurrency MOC. :

managedObjectContext = [[NSManagedObjectContext alloc]
                        initWithConcurrencyType:NSMainQueueCurrencyType];

MOC , , ( , - , MOC ). :

[managedObjectContext performBlock:^{
    // Do anything with this MOC because its protected, and
    // running on the right thread.
}];

performBlockAndWait, (dispatch_sync - ). sync, deadly embrace, performBlockAndWait .

+4

:

- (void)emptyDatabase{
    NSError * error;
    // retrieve the store URL
    NSURL * storeURL = [[self.managedObjectContext persistentStoreCoordinator] URLForPersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject]];
    // lock the current context
    [self.managedObjectContext lock];
    [self.managedObjectContext reset];//to drop pending changes
    //delete the store from the current managedObjectContext
    if ([[self.managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:&error])
    {
        // remove the file containing the data
        [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
        //recreate the store like in the  appDelegate method
        [[self.managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store
    }
    [self.managedObjectContext unlock];
}
+6

, NSManagedObjectContext . , , , Thread 5, , . NSManagedObjectContext . , mainContext , - clear .

:

  • NSManagedObjectContext .
  • , clear . :

    -(void)clear:(id)object {
        if(![[NSThread currentThread] isMainThread]) {
            [self performSelectorOnMainThread:@selector(clear:) withObject:object waitUntilDone:NO];
            return;
        }
        ...
    }
    
  • lock, unlock NSManagedObjectContext. , .

.

+4
source

All Articles