修改 coreData 实体后视图不重绘 - 可能的错误?

View doesn't redraw after modifying coreData entity - Possible Bug?

提问人:srome11 提问时间:3/23/2023 更新时间:3/23/2023 访问量:32

问:

所以老实说,我在网上找到了这个视图模型的想法,它在新的上下文中创建或加载一个 coredata 实体,然后保存结果。从本质上讲,当我想编辑对象时显示的工作表会加载相关对象,但父视图不会重新加载以反映更改。即使视图模型中的对象类型是@Published,并且我正在更改和保存上下文......

这可能是一个错误。

主视图代码


    struct MainListView: View {
    
    //Bring in coreData singleton instance
    var provider = ContactsProvider.instance
     
//    //isShowing for sheet - defuct for edit button
//    @State private var isShowing = false
    @State private var orgToEdit: OrgEntity?
    
    //Fetching and assigning to orgEntity(s)  variable
    @FetchRequest(fetchRequest: OrgEntity.all()) private var orgEntitys
    
    var body: some View {
        NavigationStack {
            
            List {
                ForEach(orgEntitys) { org  in
                    NavigationLink(destination: OrgEntityDetailView(orgEntity: org)) {
                        MainListRow(orgEntity: org)
                            .swipeActions(allowsFullSwipe: true) {
                                //Buttons for delete / edit
                                Button(role: .destructive) {
                                    do {
                                        try provider.deleteOrg(org, context: provider.newContext)
                                    } catch {
                                        print("\(error)")
                                    }
                                } label: {
                                    Label("Delete", systemImage: "trash")
                                }
                                .tint(.red)
                                Button {
                                    orgToEdit = org
                                } label: {
                                    Label("Edit", systemImage: "pencil")
                                }
                                .tint(.orange)
                            }
                        
                    }
                }
            }
            .listStyle(.insetGrouped )
            .navigationTitle("My Map")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button {
                        orgToEdit = .empty(context: provider.newContext)
                    } label: {
                        Image(systemName: "plus")
                            .font(.title2)
                    }
                }
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        
                    } label: {
                        Image(systemName: "map")
                    }

                }
            }
            .sheet(item: $orgToEdit, onDismiss: {
                orgToEdit = nil
            }, content: { org in    //passing in this closure to the view
                NavigationStack {
                    CreateOrgView(vm: .init(provider: provider, orgEntity: org ))
                }
            })
        
        }
    }
}

查看型号代码

import Foundation
import CoreData

class EditOrgViewModel: ObservableObject {
    
    
    @Published var orgEntity: OrgEntity
    
    
    private let context: NSManagedObjectContext
    private let provider: ContactsProvider
    

    let isNew: Bool
    
  
    init(provider: ContactsProvider, orgEntity: OrgEntity? = nil) {
        //set context to new background context
        self.provider = provider
        self.context = provider.newContext
        if let orgEntity,   
           let existingContactCopy =  provider.orgExists(orgEntity, in: context) {
            self.orgEntity = existingContactCopy
            self.isNew = false
        } else {
            self.orgEntity = OrgEntity(context: self.context)
            self.isNew = true
        }
            
    }
    
    func save() throws {
            try provider.persist(in: context)
        }
    
}

提供程序代码:Exists() 和 Save() 函数


    import Foundation
import CoreData
import SwiftUI

class ContactsProvider {
    
    //creating a singleton?
    static let instance: ContactsProvider = ContactsProvider()
    
    //Create the container of type NSpersistContainer
    let persistentContainer: NSPersistentContainer
    
    //computed property for viewContext - assuming for safety
    var viewContext: NSManagedObjectContext {
        persistentContainer.viewContext
    }
    
    //computed property for new context - used when editing or adding entities
    var newContext: NSManagedObjectContext {
        persistentContainer.newBackgroundContext()
    }
    
    private init() {
        persistentContainer = NSPersistentContainer(name: "ContactsDataModel")
        //Using the extension below for previews - makes a path to build a new context - in memory
        if EnvironmentValues.isPreview {
            persistentContainer.persistentStoreDescriptions.first?.url = .init(filePath: "/dev/null")
        }
        persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
        //auto saves any changes
        persistentContainer.loadPersistentStores { _, error in
            if let error {
                fatalError("Unable to load store with error: \(error )")
            }
        }
    }
    
    
    func orgExists(_ orgEntity: OrgEntity, in context: NSManagedObjectContext) -> OrgEntity? {
        try? context.existingObject(with: orgEntity.objectID) as? OrgEntity
        //try and find a org with the context passed in that matches ID - then return the org
        
    }
    
    func personExists(_ personEntity: PersonEntity, in context: NSManagedObjectContext) -> PersonEntity? {
        try? context.existingObject(with: personEntity.objectID) as? PersonEntity
    }
    
    func deleteOrg(_ orgEntity: OrgEntity, context: NSManagedObjectContext) throws {
        if let existingOrg = orgExists(orgEntity, in: context) {
            context.delete(existingOrg)
            //swift ui concurrency and async save the coredata
            Task(priority: .background) {
                try await context.perform {
                    try context.save()
                }
            }
        }
    }
    
    func deletePerson(_ personEntity: PersonEntity, context: NSManagedObjectContext) throws {
        if let existingPerson = personExists(personEntity, in: context) {
            context.delete(existingPerson)
            //swift ui concurrency and async save the coredata
            Task(priority: .background) {
                try await context.perform {
                    try context.save()
                }
            }
        }
    }
    
    func persist(in context: NSManagedObjectContext) throws {
        if context.hasChanges {
            try context.save()
        }
    }
    
    
}

//Checking to see if we are in a preview so we can make a custom context sandbox - from stackoverflow
// used to check for creating a context in memory
extension EnvironmentValues {
    static var isPreview: Bool {
        return ProcessInfo.processInfo.environment["XCODE_RUNNING _FOR_PREVIEWS"] == "1"
    }
}

iOS Swift iPhone SwiftUI 核心数据

评论


答:

0赞 srome11 3/23/2023 #1

在这里找到它:

当 SwiftUI 中的相关实体发生变化时,如何更新@FetchRequest?

还需要更新要@observedobject的行

在这里:

黑客斯威夫特

评论

2赞 Joakim Danielson 3/23/2023
不要只发布链接答案,通过简要描述链接页面的内容并解释它如何解决问题来为您的答案添加一些上下文
0赞 Community 3/29/2023
您的答案可以通过额外的支持信息得到改进。请编辑以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到有关如何写出好答案的更多信息。