SwiftUI 中的 CoreData:如何清楚地获取属性?

Posted

技术标签:

【中文标题】SwiftUI 中的 CoreData:如何清楚地获取属性?【英文标题】:CoreData in SwiftUI: How to fetch a property distinctly? 【发布时间】:2020-02-02 13:55:53 【问题描述】:

我花了好几个小时来弄清楚如何从数据模型 (CoreData) 的属性中唯一地获取值。

例如,如果我有 3 条记录,它们的 WrappedName 属性中分别包含“Apple”、“Banana”和“Apple”,则 ListView 将显示“Apple”、“Banana”和“Apple”(3 行)。

但我只想显示“Apple”和“Banana”(2 行)。

我怎样才能做到这一点?

//ListView.swift
import SwiftUI
import CoreData

struct ListView: View 
    @FetchRequest(entity: Data.entity(), sortDescriptors: []) var data: FetchedResults<Data>    
    var body: some View 
        NavigationView
            List
                ForEach(data, id: \.self)  d in
                    NavigationLink(destination: ChartView(title: d.wrappedName) 
                        Text(d.wrappedName)
                    
                
            
        
    


//Data+CoreDataProperties.swift
import Foundation
import CoreData

extension Data 

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Data> 
        return NSFetchRequest<Data>(entityName: "Data")
    

    @NSManaged public var date: Date?
    @NSManaged public var id: UUID?
    @NSManaged public var name: String?
    public var wrappedName: String 
        name ?? "Unknown"
    




【问题讨论】:

帮助提示:将extension Data 更改为extension Data: Identifiable,或者更好地添加单行extension NSManagedObject: Identifiable 以使所有NSManagedObjects 符合Identifiable 协议,您可以更改其中的一行你的List 视图到ForEach(data) d in。不是很大的改进,但更易于阅读。 【参考方案1】:

设置Published var 的自定义Notification 会更好

public init() 
    self.uniqueDict = [NSDictionary]()

    let notificationCenter = NotificationCenter.default
    notificationCenter.addObserver(self, selector: #selector(setUniqueDictValue), name: NSNotification.Name.NSManagedObjectContextObjectsDidChange, object: managedObjectContext)
    //set the uniqueDict variable
    setUniqueDictValue()


private func getEntityFetchRequest() -> NSFetchRequest<NSDictionary>
    
        let fetchRequest = NSFetchRequest<NSDictionary>(entityName: "YourModel")

        let sortDescriptor = NSSortDescriptor(key: "name", ascending: false)

        fetchRequest.sortDescriptors = [sortDescriptor]

        fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType
        fetchRequest.propertiesToFetch = ["name"]
        fetchRequest.returnsDistinctResults = true

        return fetchRequest
    
    ///Single Fetch of objects willSet uniqueDict variable
    func setUniqueDictValue()  
        do 
            try self.uniqueDict = managedObjectContext.fetch(getEntityFetchRequest())
         catch 
            fatalError("Failed to fetch entity: \(error)")
        
    

不同的结果示例项目 https://www.youtube.com/watch?v=xl3KVmBJrSg

【讨论】:

@Ray 在我回答了这个问题后,我做了一个小示例项目并上传了一个视频。 youtube.com/watch?v=-U-4Zon6dbE 看完了你的教程!但是要使用fetchRequest.returnsDistinctResults = true,它需要fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType,但随后出现错误'NSFetchedResultsController 不支持NSDictionaryResultType 的更改跟踪和获取请求'。你能给我建议吗? 因为将其切换到字典意味着您不再获得对象数组,而是获得“wrappedName”/String 的字典。需要删除 'fetchController!.delegate = self' 行。每次您想要一个新列表时,您都必须触发 initFetchedResultsController() 方法。在 ViewModel ADD '@Published var uniqueDict: [NSDictionary]' 中,向 init() 添加 'self.uniqueDict = [NSDictionary]()',将所有 'YourModel' 更改为 'NSDictionary'。在 ListView 中更改 'List(viewModel.uniqueDict, id: \.self)obj in Text((obj as NSDictionary).allValues.first as!String)' 这是另一个示例项目youtube.com/watch?v=xl3KVmBJrSg 如果没有controllerDidChangeContent,当从其他视图添加新数据时,ListView 不会更新......但这使得使用returnsDistinctResults 成为不可能......我想我需要采取不同的方法,直到@ 987654331@ 支持不同的结果。感谢您的详细说明!【参考方案2】:

您需要更改您的核心数据模型。该模型应该按照您希望在 UI 中显示的方式进行设计。不要把它设计成数据库。

在您的情况下,另一个实体名为 Fruit,其 int fruitType 是唯一键,Apple 为 1,Banana 为 2。在您的数据实体中有一个关系水果,但现在不是获取数据而是获取水果。如果您想在列表单元格中显示有关数据的内容,只需向 Fruit 类添加一个属性即可从相关数据中检索它。并且使用 KVO 观察,您可以使上下文在其相关 Data 中的某些内容发生更改时检测到 Fruit 的更改。

【讨论】:

以上是关于SwiftUI 中的 CoreData:如何清楚地获取属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 SwiftUI 中的颜色类型存储到 CoreData 中?

Swift之深入解析如何结合Core Data和SwiftUI

我如何(或应该?)用嵌套的 managedObjectContext 替换这个 CoreData SwiftUI 应用程序中的 MVVM?

SwiftUI 中的领域:UI 中仅偶尔保存对象的实时文本

如何在 SwiftUI 中使用 CoreData 更改数据值?

SwiftUI:如何将 CoreData 与动态过滤器相加?