在iOS 8扩展中访问核心数据SQL数据库(在App和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) }
请记住将此方法附加到: AppDelegate和Today Extension