Hey Team,
We are seeing some random crashes for CoreData only on iOS 9 devices. We are primarily seeing two errors when Core Data performs lightweight migration when setting up the Stack -
We have no clue about what this error could be
"Error Domain=NSCocoaErrorDomain Code=512 \"The file couldn\U2019t be saved.\"
2. The error code translates to SQLite Error code 14. [Error code is "Domain=NSCocoaErrorDomain Code=134110", "NSSQLiteErrorDomain Code=14" https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Miscellaneous/CoreData_Constants/#//apple_ref/doc/constant_group/Migration_Error_Codes , https://www.sqlite.org/rescode.html#cantopen ]
Error Domain=NSCocoaErrorDomain Code=134110 \"An error occurred during persistent store migration.\" UserInfo=
{ sourceURL=file:///var/mobile/Containers/Data/Application/BFD91E93-5977-4135-A454-5EBDF8EE53E4/Library/Database/DB.sqlite,
reason=Can't copy source store to destination store path, destinationURL=file:///var/mobile/Containers/Data/Application/BFD91E93-5977-4135-A454-5EBDF8EE53E4/Library/Database/.DB.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3,
NSUnderlyingError=0x127fd31e0 {Error Domain=NSSQLiteErrorDomain Code=14 \"(null)\"
UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/BFD91E93-5977-4135-A454-5EBDF8EE53E4/Library/Database/.DB.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3,
reason=Failed to open destination database}}}";
We don't know what could be causing these issues. Also, the directory being protected via "NSFileProtectionComplete" option does not seem to be setup right.
Some additional datapoints that we have from Crashlytics -
1. This crash happens only on iOS 9 devices
2. Almost 70-80% of the times, the user has low RAM
3. We are not able to reproduce this migration issue on our test devices
4. We dropped support for "Vaccum option" for the latest version where we are seeing the crashes
5. We are logging the metadata and noticed that the NSPersistenceFrameworkVersion also changed from 640 to 641 from our last version of the app
We would really appreciate any help/pointers in how to fix this issue. Thanks!
Snippet from CoreData stack setup is as below -
# pragma mark - Core Data Stack Setup
- (NSManagedObjectContext *)getMainContext{
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext setUndoManager:nil];
[managedObjectContext setPersistentStoreCoordinator:[self getPersistentStoreCoordinator]];
[managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
return managedObjectContext;
}
- (NSPersistentStoreCoordinator*)getPersistentStoreCoordinator{
NSPersistentStoreCoordinator *persistentStoreCoordinator = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
NSManagedObjectModel *objectModel = [[NSManagedObjectModel alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:path]];
NSDictionary *storeOptions = @{ NSMigratePersistentStoresAutomaticallyOption: @YES,
NSInferMappingModelAutomaticallyOption: @YES };
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel];
NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[self storeURL]
options:storeOptions
error:&error];
if (!persistentStore) {
NSLog(@"error: %@", error);
}
return persistentStoreCoordinator;
}
-(NSURL *)storeURL{
NSString *databaseFileName = @"DB.sqlite";
NSString *appDatabaseFilePath = [[self sharedDatabasePath] stringByAppendingPathComponent:databaseFileName];
return [NSURL fileURLWithPath:appDatabaseFilePath];
}
- (NSString *)sharedDatabasePath{
NSString *sharedDocumentsPath = nil;
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
sharedDocumentsPath = [libraryPath stringByAppendingPathComponent:@"Database"] ;
NSFileManager *manager = [NSFileManager defaultManager];
BOOL isDirectory;
if (![manager fileExistsAtPath:sharedDocumentsPath isDirectory:&isDirectory] || !isDirectory) {
NSError *error = nil;
NSDictionary *attr = [NSDictionary dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey];
[manager createDirectoryAtPath:sharedDocumentsPath
withIntermediateDirectories:YES
attributes:attr
error:&error];
if (error)
NSLog(@"Error creating directory path: %@", [error localizedDescription]);
}
return sharedDocumentsPath;
}