【问题标题】:How to get data by giving id(UUID) in the same CoreData model?如何通过在同一 CoreData 模型中提供 id(UUID) 来获取数据?
【发布时间】: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

标签: swift core-data swiftui widgetkit


【解决方案1】:

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

解决方案 #1 - 核心数据

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

然后,您将能够获取与 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 值,谢谢您的帮助!
猜你喜欢
  • 2022-06-22
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-17
相关资源
最近更新 更多