从不同的文件 SwiftUI 调用核心数据对象

Posted

技术标签:

【中文标题】从不同的文件 SwiftUI 调用核心数据对象【英文标题】:Call Core Data Objects from different file SwiftUI 【发布时间】:2020-05-13 16:23:44 【问题描述】:

现在,我必须对同一个视图文件执行 CRUD,因为每次我尝试将其移动到不同的文件并使用函数在视图上调用它时都会出错。关于我作为 cmets 编写的代码,也有一些解释:

import SwiftUI

struct ContentView: View 

@ObservedObject var myClass = MyClass()

@FetchRequest(
    entity: ProgrammingLanguage.entity(),
    sortDescriptors: [
        NSSortDescriptor(keyPath: \ProgrammingLanguage.id, ascending: true)
    ]
) var languages: FetchedResults<ProgrammingLanguage>

@Environment(\.managedObjectContext) var managedObjectContext

var body: some View 

    NavigationView 
        VStack 
            List(languages, id: \.self)  language in
                Text(self.language.name ?? "")
            
        
    
    .onAppear
        // Data not refreshed
        self.myClass.createData()
    



class MyClass: ObservableObject 

@FetchRequest(
    entity: ProgrammingLanguage.entity(),
    sortDescriptors: [
        NSSortDescriptor(keyPath: \ProgrammingLanguage.id, ascending: true)
    ]
) var languages: FetchedResults<ProgrammingLanguage>

@Environment(\.managedObjectContext) var managedObjectContext

func createData() 
    for i in 1...5 
        let language = ProgrammingLanguage(context: self.managedObjectContext)
        language.id = Int32(i)           // << here !!
        language.name = "\(i) SwiftUI"
        do 
            try self.managedObjectContext.save()
         catch 
        
    


func readData() 
    // How can I return the objects here? Not in a loop, but as a fetch request so I can use that fetch request on other views


如何将核心数据对象从 MyClass 调用到 ContentView 而不必一遍又一遍地重复相同的代码?

现在在 .onAppear() 上它读取函数但不刷新数据

【问题讨论】:

您认为 FetchRequest 的好处在于,如果它发生变化,您的视图将更新并显示新项目。如果您想在 MyClass 类中获取 CoreData 对象,您可以这样做,但是您需要使用 ObservableObject 通知您的视图有关更改。 我该怎么做?我理解将它放在同一个视图上的好处,但是如果你必须对 10-100 个文件做同样的事情,那就太可怕了,除了我必须更新每个单独的文件@davidev 为什么要在多个视图中显示它?我有一个获取一个实体的 MainView,然后我将一个对象传递给显示数据的子视图。我不需要多次获取它。 这可能会更好,我怎样才能将它从 MainView 传递到子视图? @davidev 【参考方案1】:

我会保留 @FetchRequest,因为它是 SwiftUI 的一个非常酷的功能。当您遍历您的项目时,您会将它们传递给您的子视图。

import SwiftUI

struct ContentView: View 

@FetchRequest(
    entity: ProgrammingLanguage.entity(),
    sortDescriptors: [
        NSSortDescriptor(keyPath: \ProgrammingLanguage.id, ascending: true)
    ]
) var languages: FetchedResults<ProgrammingLanguage>

@Environment(\.managedObjectContext) var managedObjectContext

init() 

    //here you can call your method of your Manager to create your example data 
    //you to give you an example
    //CoreDataManager.shared.createTestData() 

    for i in 1...5 
        let language = ProgrammingLanguage(context: self.managedObjectContext)
        language.id = Int32(i)           // << here !!
        language.name = "\(i) SwiftUI"
        do 
            try self.managedObjectContext.save()
         catch 
        
    



    var body: some View 

        NavigationView 
            VStack 
                List(languages, id: \.self)  language in
                    //Here we pass a single language entity to our subview
                    //If that subview makes changes to that object, these changes will detected in this view here
                    Subview(language: language)
                
            
        
    


struct Subview: View 

    var language: ProgrammingLanguage

    var body: some View 
    
        Text(self.language.name ?? "")
    

您只需将语言传递给您的子视图,就可以在那里访问这些值。 Language 是 ProgrammingLanguage 类的对象,它由 CoreData 自动创建。如果您对该对象进行更改,即使在子视图中,这些更改也可以显示在ContentView 中。如果需要,您还可以将您的语言作为数组传递给您的子视图。

编辑:我没有测试过该示例代码。它应该只是给你一个简短的例子,如何将你的对象传递到下一个视图,并在那里显示这些属性。

但是,外包您的 CoreData 活动确实是有意义的。我使用了一个 CoreData Manager,我使用 Singleton 方法实现了它,它处理创建新对象、保存上下文...

【讨论】:

如果我想在另一个类上定义一个函数并在那个子视图上运行它怎么办?假设在 mainView 中该 NavigationView 的 .onAppear 上。一个示例可能是创建/删除数据。所以我在 1 个类中有 1 个函数,我可以在多个文件/视图上调用它 是的,这是可能的。您可以在视图的 init 方法中调用该 create 方法来创建示例数据。请参阅上面的 init 方法。 在哪个init方法中?请参考我在帖子中的示例,如何在另一个类的 void 函数上调用 onAppear 上的循环,以便创建这些值? @Spyky 您可以将其添加到 init 方法中的任何视图结构中。您也可以在您的子视图中调用它,这将对 CoreData 进行更改,这些更改将被 FetchResult 检测到,并相应地更新视图 我想你不明白我的意思。我不想使用视图,我试图将逻辑移到视图之外。我用新代码更新了上面的问题。如果您查看class MyClass 我有函数createData,它编译但没有显示数据,也许UI 不知道更改?另外,如果您看到,我在两个文件上重复相同的提取请求代码,我如何才能仅在 readData() 上实现此提取请求?

以上是关于从不同的文件 SwiftUI 调用核心数据对象的主要内容,如果未能解决你的问题,请参考以下文章

将核心数据从 Swift 迁移到 SwiftUI

SwiftUI - 如何限制 ForEach 中显示的对象数量

SwiftUI 列表,其中包含从核心数据中获取的部分

从核心数据中删除/添加到核心数据后,带有列表的 SwiftUI TabView 不刷新

将核心数据对象提取到 SwiftUI 选择器中

SwiftUI 从 URL 加载单个对象 JSON