如何通过在同一 CoreData 模型中提供 id(UUID) 来获取数据?

Posted

技术标签:

【中文标题】如何通过在同一 CoreData 模型中提供 id(UUID) 来获取数据?【英文标题】:How to get data by giving id(UUID) in the same CoreData model? 【发布时间】:2021-01-07 19:30:03 【问题描述】:

我目前正在使用 SwiftUI 开发应用程序。

我想创建一个函数来获取CoreData 模型中的一些数据,并在同一CoreData 模型中给出一个ID。


这是我想做的一个示例函数(不起作用,只是为了解释)

func getDataById(id:UUID) -> String  // give an id in model
    return task                       // return an task in model which has the same id of the argument

如果我有这个CoreData 模型:

id (UUID) |任务(字符串)


001 |会议

002 |购物

003 |烹饪

如果我使用如下函数:

let task = getDataById(id:001)

print(task) // meeting

它是这样工作的。


我的目标是在Widget 获取数据时使用id 数据将一些task 数据显示为WIdget 中的列表。

(当我们使用picker 时,就像在列表和标签中显示的值一样给selection 赋值)

代码如下:

IntentHandler.swift

import WidgetKit
import SwiftUI
import CoreData
import Intents

class IntentHandler: INExtension,ConfigurationIntentHandling 
    
    var moc = PersistenceController.shared.managedObjectContext

    func provideNameOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) 

        // let request = NSFetchRequest<TimerEntity>(entityName: "TodoEntity")
        let request = NSFetchRequest<TodoEntity>(entityName: "TodoEntity")
        var nameIdentifiers:[NSString] = []

        do
            let results = try moc.fetch(request)

            for result in results
                nameIdentifiers.append(NSString(string: result.id?.uuidString ?? "")) // I want display task data using id data here.
            
        
        catch let error as NSError
            print("Could not fetch.\(error.userInfo)")
        

        let allNameIdentifiers = INObjectCollection(items: nameIdentifiers)
        completion(allNameIdentifiers,nil)
    
    
    override func handler(for intent: INIntent) -> Any 
        return self
    


- 已更新 -

Persistence.swift(宿主应用)

import CoreData
import Foundation

class PersistenceController 
    static let shared = PersistenceController()

    private init() 

    private let persistentContainer: NSPersistentContainer = 
        let storeURL = FileManager.appGroupContainerURL.appendingPathComponent("TodoEntity")

        let container = NSPersistentContainer(name: "Todo")
        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]
        container.loadPersistentStores(completionHandler:  storeDescription, error in
            if let error = error as NSError? 
                print(error.localizedDescription)
            
        )
        return container
    ()


extension PersistenceController 
    var managedObjectContext: NSManagedObjectContext 
        persistentContainer.viewContext
    


extension PersistenceController 
    var workingContext: NSManagedObjectContext 
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        context.parent = managedObjectContext
        
        return context
    


extension FileManager 
    static let appGroupContainerURL = FileManager.default
        .containerURL(forSecurityApplicationGroupIdentifier: "group.com.sample.Todo")!


Xcode:版本 12.0.1

ios:14.0

【问题讨论】:

"如果我有这个 CoreData 模型..." - 它在哪里调用,你如何访问它?有任何获取请求吗? 您需要在获取请求中使用NSPredicate。如果您发布有关模型的更多详细信息,有人可能会帮助您弄清楚如何设置谓词。 @pawello2222,@Tom Harrington,感谢您的评论,我更新了我的问题。 getDataById 在做什么? @Pranav Kasetti,getDataById 在模型中接收 id,然后在同一模型的同一行中返回 task 【参考方案1】:

您需要的是两个实体之间的关系

解决方案 #1 - 核心数据

您可以直接在核心数据级别创建TodoTask 之间的关系。您没有在问题中发布足够的详细信息来进一步扩展此解决方案,但是,您可以遵循以下答案:

One-to-Many and Many-to-Many Core Data Relationships Core Data relationships (swift)

然后,您将能够获取与 Todo 项目关联的 Task,然后您只需直接从 Task 对象中检索必要的属性。

解决方案 #2 - 地图

另一种可能的解决方案是获取IntentHandler 中的所有Task 对象,然后将您的Todo 对象映射到获取的任务。

您可以尝试以下方法(仅作为示例,因为代码不可测试):

class IntentHandler: INExtension, ConfigurationIntentHandling 
    
    var moc = PersistenceController.shared.managedObjectContext

    func provideNameOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) 
        var nameIdentifiers: [NSString] = []

        do 
            // fetch todos
            let todosRequest = NSFetchRequest<TodoEntity>(entityName: "TodoEntity")
            let todos = try moc.fetch(todosRequest)

            // fetch tasks
            let tasksRequest = NSFetchRequest<TaskEntity>(entityName: "TaskEntity")
            let tasks = try moc.fetch(tasksRequest)
            let tasksDict = Dictionary(grouping: tasks, by: \.id)

            // map `todos` to `tasks`
            nameIdentifiers = todos
                .compactMap  todo in
                    guard let id = todo.id,
                        let task = tasksDict[id]?.first?.task
                    else  
                        return nil 
                    
                    return NSString(string: task)
                
        
        catch let error as NSError 
            print("Could not fetch.\(error.userInfo)")
        

        let allNameIdentifiers = INObjectCollection(items: nameIdentifiers)
        completion(allNameIdentifiers, nil)
    
    
    override func handler(for intent: INIntent) -> Any 
        return self
    

【讨论】:

感谢您的回答,不幸的是,代码写错了……我现在刚刚在 IntentHandler.swift 中更新了let request = NSFetchRequest&lt;TodoEntity&gt;(entityName: "TodoEntity")。被收集。所以我的CoreData 只有一个Entity(TodoEntity)。你能告诉我在这种情况下应该如何解决吗?我很抱歉我的错误。 最后我可以在同一个id 中使用Dictionary()compactMap 在同一个Entity 中显示task 值,谢谢您的帮助!

以上是关于如何通过在同一 CoreData 模型中提供 id(UUID) 来获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 Core Data 的人想要在同一个托管对象模型中使用多个持久存储?

在 CoreData 中迁移实体父级

通过同一模型的两个 has_many 关系

如何使用静态库(iOS)在应用程序中隐藏核心数据模型?

如何在刚刚创建目标实体模型的 Coredata 中迁移实体

将两个 CoreData 关系(具有反向关系)分配给同一个实体