Master data is not saved in the distribution structure

I have a very strange problem where Core Data works fine in development (debug) builds, but on distributions (releases) distributed across TestFlight my NSManagedObjectContext objects are not saved correctly.

I see two problems:

  • NSManagedObjectContextDidSaveNotification is not dispatched when the context is saved.
  • Data is not persisted between runs.

What could be causing this ONLY in distribution assemblies? As far as I know, provisioning profiles do not affect master data.

Here's the two relevant functions of my underlying data stack:

- (void)initializeCoreData
{
    NSLog(@"%s", __FUNCTION__);

    if ([self managedObjectContext]) return;

    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"XXX" withExtension:@"momd"];
    NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    NSAssert(mom, @"%@:%@ No model to generate a store from", [self class], NSStringFromSelector(_cmd));

    NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
    NSAssert(coordinator, @"Failed to initialize coordinator");

    self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    self.privateContext.persistentStoreCoordinator = coordinator;

    self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    self.managedObjectContext.parentContext = self.privateContext;



    // Persistence store
    NSMutableDictionary *options = [NSMutableDictionary dictionary];
    options[NSMigratePersistentStoresAutomaticallyOption] = @YES;
    options[NSInferMappingModelAutomaticallyOption] = @YES;
//  options[NSSQLitePragmasOption] = @{ @"journal_mode":@"DELETE" };

    NSURL *documentsURL = [[NSFileManager.defaultManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    // TODO: use real store url
    NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"Data2.sqlite"];

    NSError *error = nil;
    NSAssert([coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error], @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);


}

- (void)save;
{
    if (![[self privateContext] hasChanges] && ![[self managedObjectContext] hasChanges]) return;

    [[self managedObjectContext] performBlockAndWait:^{
        NSError *error = nil;

        NSAssert([[self managedObjectContext] save:&error], @"Failed to save main context: %@\n%@", [error localizedDescription], [error userInfo]);

        [[self privateContext] performBlock:^{
            NSError *privateError = nil;
            NSAssert([[self privateContext] save:&privateError], @"Error saving private context: %@\n%@", [privateError localizedDescription], [privateError userInfo]);
        }];
    }];
}

      

Any thoughts?

Update: I tried running a debug build and save something in the Core Data database and it persists perfectly between runs, then deployed the release build without uninstalling the app so the data and database looks empty, then deployed the debug build again and existing the database is loaded fine. It looks like the release build has a problem with accessing the database file for some reason. Any thoughts why this is happening?

+3


source to share


1 answer


NSAssert

usually does not run in release builds because it NS_BLOCK_ASSERTIONS

is defined as part of the default Xcode template. Or from the docs

IMPORTANT Do not call functions with side effects in the parameter state of this macro. The condition parameter is not evaluated when assertions are disabled, so if you call functions with side effects, those functions will never be called when the project is created in a non-debug configuration.



Basically don't do what you need to do in Assert. This is a debug test. You really want to be a little softer here, and a soft dip.

if([[self managedObjectContext] save:&error] == NO){ 
    NSLog(@"Failed to save main context: %@\n%@", [error localizedDescription], [error userInfo]);
}
else {
    [[self privateContext] performBlock:^{
        NSError *privateError = nil;
        if([[self privateContext] save:&privateError] == NO){ 
            NSLog(@"Error saving private context: %@\n%@", [privateError localizedDescription], [privateError userInfo]);
        }
    }];
}

      

+4


source







All Articles