扩展中的CoreData:如何在共享组中使用数据库
CoreData in extension: how to use database in shared group
正在尝试在键盘扩展中使用 CoreData
。我想数据库文件必须在同一个地方 - 扩展和包含应用程序。那个地方是应用程序组。我是用苹果账户做的。我设置在应用程序和扩展程序中使用它(歌唱和功能中的复选框)。但它在应用程序和扩展程序中并不相同,或者我误解了一些东西。这是一些代码。
在我的应用程序中,我创建了一个惰性变量来将 DB
文件 URL
存储在 AppDelegate
文件中:
lazy var secureAppGroupPersistentStoreURL : URL = {
let fileManager = FileManager.default
let groupDirectory = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.xxxxx")!
//xxxxx - is my real bundle identificator
return groupDirectory.appendingPathComponent("SharedData.sqlite")
}()
我认为它必须指向共享文件夹中的文件。然后我像这样创建 PersistentContaner
lazy var testPersistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "testDataShare")
let description = NSPersistentStoreDescription(url: secureAppGroupPersistentStoreURL)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
我使用 NSPersistentStoreDescription
设置数据库文件名。至少我相信它是这样工作的:)
之后,在我的 SceneDelegate 文件中,我像这样使用这个容器(我的测试实体称为实体,只有一个名为名称的属性):
//debug
let testContext = (UIApplication.shared.delegate as! AppDelegate).testPersistentContainer.viewContext
let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest()
if let keyboards = try? testContext.fetch(fetchRequest){
print("fetch: \(keyboards.debugDescription)")
}else{
print("fetched nothin")
}
let testEntity = Entity(context: testContext)
testEntity.name = "test from app"
_ = try? testContext.save()
只是为了测试,我每次启动我的应用程序时都会再插入一个对象。它现在工作正常。我在控制台中得到这样的调试信息:
fetch: [ (entity: Entity; id:
0x9f53fc35e433bbae
; data:
), (entity: Entity; id:
0x9f53fc35e43fbbae
; data:
), (entity: Entity; id:
0x9f53fc35e43bbbae
; data:
), (entity: Entity; id:
0x9f53fc35e427bbae
; data:
), (entity: Entity; id:
0x9f53fc35e423bbae
; data:
), (entity: Entity; id:
0x9f53fc35e42fbbae
; data:
), (entity: Entity; id:
0x9f53fc35e42bbbae
; data: {
name = "test from app"; })]
我在我的扩展中做了同样的事情,添加了惰性变量 secureAppGroupPersistentStoreURL
,创建了 PersistentContainer
到 KeyboardViewController
并尝试在 viewDidLoad()
中做同样的获取但是它不显示任何结果。
override func viewDidLoad() {
super.viewDidLoad()
let context = self.testPersistentContainer.viewContext
let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest()
if let keyboards = try? context.fetch(fetchRequest){
print("fetch: \(keyboards.debugDescription)")
}else{
print("fetched nothin")
}
//...
}
当我开始扩展模拟时,它打印如下:
2020-03-06 01:17:25.835412+0300 Keyboard[3482:275851] Failed to
inherit CoreMedia permissions from 3042: (null)
fetch: []
我希望我在应用程序中保存的对象能够在扩展程序中获取,反之亦然。
我对数据库文件做错了什么?
确保您的键盘扩展已启用完全访问权限。如果没有,恐怕您无法访问共享数据,甚至无法保存到扩展程序和父应用程序之间的 UserDefaults。
正在尝试在键盘扩展中使用 CoreData
。我想数据库文件必须在同一个地方 - 扩展和包含应用程序。那个地方是应用程序组。我是用苹果账户做的。我设置在应用程序和扩展程序中使用它(歌唱和功能中的复选框)。但它在应用程序和扩展程序中并不相同,或者我误解了一些东西。这是一些代码。
在我的应用程序中,我创建了一个惰性变量来将 DB
文件 URL
存储在 AppDelegate
文件中:
lazy var secureAppGroupPersistentStoreURL : URL = {
let fileManager = FileManager.default
let groupDirectory = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.xxxxx")!
//xxxxx - is my real bundle identificator
return groupDirectory.appendingPathComponent("SharedData.sqlite")
}()
我认为它必须指向共享文件夹中的文件。然后我像这样创建 PersistentContaner
lazy var testPersistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "testDataShare")
let description = NSPersistentStoreDescription(url: secureAppGroupPersistentStoreURL)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
我使用 NSPersistentStoreDescription
设置数据库文件名。至少我相信它是这样工作的:)
之后,在我的 SceneDelegate 文件中,我像这样使用这个容器(我的测试实体称为实体,只有一个名为名称的属性):
//debug
let testContext = (UIApplication.shared.delegate as! AppDelegate).testPersistentContainer.viewContext
let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest()
if let keyboards = try? testContext.fetch(fetchRequest){
print("fetch: \(keyboards.debugDescription)")
}else{
print("fetched nothin")
}
let testEntity = Entity(context: testContext)
testEntity.name = "test from app"
_ = try? testContext.save()
只是为了测试,我每次启动我的应用程序时都会再插入一个对象。它现在工作正常。我在控制台中得到这样的调试信息:
fetch: [ (entity: Entity; id: 0x9f53fc35e433bbae ; data: ), (entity: Entity; id: 0x9f53fc35e43fbbae ; data: ), (entity: Entity; id: 0x9f53fc35e43bbbae ; data: ), (entity: Entity; id: 0x9f53fc35e427bbae ; data: ), (entity: Entity; id: 0x9f53fc35e423bbae ; data: ), (entity: Entity; id: 0x9f53fc35e42fbbae ; data: ), (entity: Entity; id: 0x9f53fc35e42bbbae ; data: { name = "test from app"; })]
我在我的扩展中做了同样的事情,添加了惰性变量 secureAppGroupPersistentStoreURL
,创建了 PersistentContainer
到 KeyboardViewController
并尝试在 viewDidLoad()
中做同样的获取但是它不显示任何结果。
override func viewDidLoad() {
super.viewDidLoad()
let context = self.testPersistentContainer.viewContext
let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest()
if let keyboards = try? context.fetch(fetchRequest){
print("fetch: \(keyboards.debugDescription)")
}else{
print("fetched nothin")
}
//...
}
当我开始扩展模拟时,它打印如下:
2020-03-06 01:17:25.835412+0300 Keyboard[3482:275851] Failed to inherit CoreMedia permissions from 3042: (null) fetch: []
我希望我在应用程序中保存的对象能够在扩展程序中获取,反之亦然。
我对数据库文件做错了什么?
确保您的键盘扩展已启用完全访问权限。如果没有,恐怕您无法访问共享数据,甚至无法保存到扩展程序和父应用程序之间的 UserDefaults。