在iOS 8扩展中访问核心数据SQL数据库(在应用程序和Widget扩展之间共享数据)

问题:

无法在“今日视图”中的“Widget扩展”中访问应用程序的“核心数据”数据库。

应用程序本身能够在iOS 8下正常读写数据库,但扩展将无法创build存储,导致错误,无法写入文件。

日志如下:

Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn't be completed. (Cocoa error 512.)" reason = "Failed to create file; code = 2 

小部件无法访问NSDocuments目录,这是通常存储数据库的地方。

解决scheme是首先创build一个应用程序组

转到:项目 – 目标 – 应用程序组 – 添加新的容器

将容器命名为“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后丢失所有应用程序数据。

UPDATE

rdar:// 18750178

UPDATE

看起来像在iOS 8.1中修复,苹果的家伙给我留言,并要求检查在iOS 8.1中的问题,不pipe它是否修复(相当粗鲁不是?)。 我没有testing过,所以请记住。 无论如何,保持存储在AppGroups是一个死的主意,如果你是支持有缺陷的iOS 8.0

更改

 [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) } 

请记住将此方法附加到: AppDelegateToday Extension