问题:
无法从Today View小部件中访问应用程序的Core Data数据库。
在iOS 8下,应用程序本身能够像往常一样读写数据库,但扩展程序将无法创建存储,并显示错误“无法写入文件”。
日志如下:
Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)"
reason = "Failed to create file; code = 2
问题:
无法从Today View小部件中访问应用程序的Core Data数据库。
在iOS 8下,应用程序本身能够像往常一样读写数据库,但扩展程序将无法创建存储,并显示错误“无法写入文件”。
日志如下:
Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)"
reason = "Failed to create file; code = 2
小部件无法访问NSDocuments目录,这通常是存储数据库的位置。
解决方法是首先创建一个应用程序组。
前往: 项目 - 目标 - 应用程序组 - 添加新容器
为容器命名,例如:'group.mycontainer'。
为小部件的目标重复此过程,使用相同的容器名称。
然后将您的数据库写入您的组容器中。
因此:
NSURL *storeURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSAllDomainsMask] lastObject];
storeURL = [storeURL URLByAppendingPathComponent:@"db.sqlite"];
成为:
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.mycontainer"];
storeURL = [storeURL URLByAppendingPathComponent:@"db.sqlite"];
初始化存储应该像这样:
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.mycontainer"];
storeURL = [storeURL URLByAppendingPathComponent:@"db.sqlite"];
NSPersistentStore *store = nil;
store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&error]
刚刚发现,使用标准iOS备份程序时,不会备份应用组文件。
请记住,如果你将持久存储保留在应用组容器中,则用户在恢复iOS后可能会丢失所有应用数据。
更新
rdar://18750178
更新
看起来在iOS 8.1中已经修复了,苹果的工作人员给我发消息要求我在iOS 8.1中检查问题是否已经解决(相当无礼,不是吗?)。我还没有测试过,所以请注意。无论如何,在支持有缺陷的iOS 8.0的情况下,将存储保留在AppGroups中是一个不好的想法。
更改
[MagicalRecord setupCoreDataStackWithStoreNamed:@"Database"];
为了
- (void)setupCoreDataStack
{
if ([NSPersistentStoreCoordinator MR_defaultStoreCoordinator] != nil)
{
return;
}
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.yourgroup"];
storeURL = [storeURL URLByAppendingPathComponent:@"Database.sqlite"];
[psc MR_addSqliteStoreNamed:storeURL withOptions:nil];
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:psc];
[NSManagedObjectContext MR_initializeDefaultContextWithCoordinator:psc];
}
同样适用于Swift:
private func setupCoreDataStack() {
if NSPersistentStoreCoordinator.MR_defaultStoreCoordinator() != nil {
return
}
let managedObjectModel = NSManagedObjectModel.MR_defaultManagedObjectModel()
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
var storePath = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier(PBOSharedSuiteGroupName)
storePath = storePath!.URLByAppendingPathComponent("AppName.sqlite")
var error: NSError?
persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storePath, options: nil, error: &error)
NSPersistentStoreCoordinator.MR_setDefaultStoreCoordinator(persistentStoreCoordinator)
NSManagedObjectContext.MR_initializeDefaultContextWithCoordinator(persistentStoreCoordinator)
}
请记得将此方法附加到AppDelegate和Today Extension两个文件中。