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

How to get data by giving id(UUID) in the same CoreData model?

我目前正在使用 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) | task (String)


001 | meeting

002 | shopping

003 | cooking

如果我使用如下函数:

let task = getDataById(id:001)

print(task) // meeting

它是这样工作的。


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

(当我们使用 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

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

解决方案 #1 - 核心数据

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

然后,您将能够获取与 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
    }
}