扩展中的CoreData:如何在共享组中使用数据库

Posted

技术标签:

【中文标题】扩展中的CoreData:如何在共享组中使用数据库【英文标题】:CoreData in extension: how to use database in shared group 【发布时间】:2020-03-05 22:25:24 【问题描述】:

尝试在键盘扩展中使用CoreData。我猜数据库文件必须在一个地方同时用于扩展和包含应用程序。那个地方是应用程序组。我是在 Apple 帐户中制作的。我在应用程序和扩展程序中都设置了使用它(Singing and Capabilities 中的复选框)。但是在应用程序和扩展程序中不一样,或者我误解了一些东西。这是一些代码。

在我的应用程序中,我创建了一个惰性变量来将 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 文件中,我像这样使用这个容器(我的测试实体称为 Entity,只有一个名为 name 的属性):

//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()

只是为了测试,我每次启动我的应用程序时都会插入一个对象。它现在工作正常。我在控制台中得到这样的调试信息:

获取:[(实体:实体;id: 0x9f53fc35e433bae ;数据: ), (实体:实体;ID: 0x9f53fc35e43fbbae ;数据: ), (实体:实体;ID: 0x9f53fc35e43bbbae ;数据: ), (实体:实体;ID: 0x9f53fc35e427bae ;数据: ), (实体:实体;ID: 0x9f53fc35e423bae ;数据: ), (实体:实体;ID: 0x9f53fc35e42fbbae ;数据: ), (实体:实体;ID: 0x9f53fc35e42bbbae ;数据: name = "从应用程序测试"; )]

我在我的扩展中做了同样的事情,添加了惰性变量secureAppGroupPersistentStoreURL,创建了PersistentContainerKeyboardViewController,并尝试在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 键盘[3482:275851] 失败 从 3042 继承 CoreMedia 权限:(空) 获取:[]

我希望我保存在应用程序中的对象能够在扩展程序中获取,反之亦然。

我对数据库文件做错了什么?

【问题讨论】:

您的键盘扩展是否启用了完全访问权限?如果不是,恐怕您无法访问共享数据,甚至无法在扩展程序和父应用程序之间保存到 UserDefaults。 @user3344236 是的。我知道我需要它来共享数据。 哦,是的!这很愚蠢,但我在选择另一个设备进行模拟后忘记再次检查完全访问权限(或者我重置了模拟,不确定我究竟是如何丢失它的)。我真的很确定它是开着的,但它不是。打开它后,我获取了我的实体。把它像一个答案一样发布,我会给你一个赏金。 对了,我仍然收到消息:无法从 23131 继承 CoreMedia 权限:(null)你不知道它是什么吗? 检查***.com/questions/26091463/…显然与App Groups实体有关 【参考方案1】:

确保您的键盘扩展已启用完全访问权限。如果不是,恐怕您无法访问共享数据,甚至无法保存到扩展程序和父应用程序之间的 UserDefaults。

【讨论】:

它有帮助。每次您在模拟中重置设备或在其他设备上开始模拟时 - 此标志重置为 false。对不起,赏金已过期,我不能给你奖励。 这没有帮助

以上是关于扩展中的CoreData:如何在共享组中使用数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何向组中的特定用户授予文件权限?

WatchKit 核心数据同步

如何在iOS上的共享应用程序组中保存文件并从中读取[重复]

使用 CoreData 时如何与 Watch OS 2 共享数据以显示在 WKInterfaceTable 中

如何根据另一个实例组中的实例数来扩展实例组

iOS8 扩展:将 CoreData 与包含的应用程序同步