问题:
无法从今日视图中的小部件扩展中访问应用程序的核心数据数据库。
应用本身在iOS 8下可以正常读写数据库,但是扩展无法创建存储,报错,无法写入文件。
日志如下:
Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)"
reason = "Failed to create file; code = 2
问题:
无法从今日视图中的小部件扩展中访问应用程序的核心数据数据库。
应用本身在iOS 8下可以正常读写数据库,但是扩展无法创建存储,报错,无法写入文件。
日志如下:
Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)"
reason = "Failed to create file; code = 2
小部件无法访问 NSDocuments 目录,这是人们通常存储其数据库的地方。
解决方法是先创建一个App Group
转到:项目 - 目标 - 应用程序组 - 添加新容器
命名容器,即'group.mycontainer'
使用与容器相同的名称对 Widget 的 Target 重复该过程。
然后将您的数据库写入您的组容器。
所以:
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 中已修复,Apple 人员给我发消息并要求检查 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];
}
斯威夫特也是如此:
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