We found and fix the problem now. The problem is caused by my misunderstanding of Core Data. We used to re-use tutorial's source code. When the system is work, we have no time to get deep understand of it.
The problem is we can't use Container App's managed object context. To fix it we use following code:
replace
[((MDAppDelegate*)appController) mainQueueContext] ;
to
[self mainQueueContext] ;
Then, add following...
- (NSManagedObjectContext *)mainQueueContext {
if (_mainQueueContext != nil) {
return _mainQueueContext;
}
_mainQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainQueueContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
[_mainQueueContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
return _mainQueueContext; }
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL;
NSString *containerPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.<your project group ID>"].path;
NSString *sqlitePath = [NSString stringWithFormat:@"file://%@/%@", containerPath, @"<Your database file>.sqlite"];
storeURL = [NSURL URLWithString:sqlitePath];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = @{
NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES
};
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error]) {
abort();
}
NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:storeURL.path error:&error]) {
// Handle error
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL;
NSString *containerPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.<your project group ID>"].path;
NSString *modelPath = [NSString stringWithFormat:@"file://%@/%@", containerPath, @"<Your database file>.momd"];
modelURL = [NSURL URLWithString:modelPath];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
Another Important issue is the Container App is still using the Core Data store located in application's Documents directory. The extension can't access it. So, we migrate the store to group shared folder using below lines:
NSString *directoryShared = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.<your project group ID>"].path;
NSString *storePathShared = [NSString stringWithFormat:@"file://%@/%@", directoryShared, @"<Your database file>.sqlite"];
NSURL *storeUrlShared = [NSURL URLWithString:storePathShared];
[_persistentStoreCoordinator migratePersistentStore:store
toURL:storeUrlShared
options:options
withType:NSSQLiteStoreType
error:&error];
if (error != nil) {
NSLog(@"Error when migration to groupd url %@, %@", error, [error userInfo]);
}
We just leave the original database alone, let the container app keep using it. there are some better way to achieve it. like:
Migrating NSPersistentStore from application sandbox to shared group container