按下按钮时 SwiftUI 2.0 iOS 14 Core 数据删除实例

Posted

技术标签:

【中文标题】按下按钮时 SwiftUI 2.0 iOS 14 Core 数据删除实例【英文标题】:SwiftUI 2.0 iOS 14 Core data delete instance on button press 【发布时间】:2021-01-11 05:00:08 【问题描述】:

我试图弄清楚如何通过调用 ViewModel 中的方法来删除核心数据对象的实例。我设法将实例的 id 获取到我的方法可能只是在语法上苦苦挣扎。我正在使用 Xcode 12.3 ios 14.3、SwiftUI 2.0 不再使用 SceneDelegate 或 AppDelegate

这是我的视图模型的样子:

import SwiftUI
import CoreData

class ViewModel : ObservableObject
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Counter.entity(), sortDescriptors: [
        
        NSSortDescriptor(
            keyPath: \Counter.id,
            ascending: true),
        NSSortDescriptor(
            keyPath:\Counter.windowType,
            ascending: true )
    ]) var counters: FetchedResults<Counter>

    //.....




    

以下是我尝试并得到此错误的方法

+entityForName: nil 不是用于搜索实体名称“Counter”的合法 NSPersistentStoreCoordinator

在调试器中单步执行代码后,这是我打印出 CounterRequested 时得到的结果

(实体:计数器;谓词:(id ==“C4BE9AFF-8A8E-4413-AFA3-AC90850C482E”);sortDescriptors:((null));类型:NSManagedObjectResultType;)

id 匹配

然后它在 do block 的第一行崩溃

func deleteCounter(id: UUID)  
    let counterRequested: NSFetchRequest<Counter> = Counter.fetchRequest()
    counterRequested.predicate = NSPredicate(format: "id=%@", id.uuidString)
  
    do 
        let savedCounters = try  self.viewContext.fetch(counterRequested)
        
        for counter in savedCounters 
            self.viewContext.delete(counter)
        
        try self.viewContext.save()
     catch 
      
        print(error)
    
 

这是我从这里得到我的身份证的地方。我可以在这里通过整个柜台吗?不确定在我的计数器视图中引用什么类型?

List 
       ForEach(counters, id: \.self)counter in
                    
          CounterCell(id: counter.id!, windowType: counter.windowType!, location: counter.location!, pickedImg: counter.pickedImg!, price: counter.price!, qty: counter.qty!, subtotal: counter.subtotal!) .listRowInsets(.init(top: 0,
                                                                                                                                                                                                                            leading: 0,
                                                                                                                                                                                                                                          bottom: 20,
                                                                                                                                                                                                                                          trailing: 0))

这是我要调用删除方法的视图

struct CounterCell: View 
@Environment(\.colorScheme) var colorScheme
@State private var stepperValue = 0
@StateObject var estimatorData = EstimatorViewModel()

var id: UUID = UUID()
var windowType: String = "Window Type"
var location: String = "Location"
var pickedImg: String = "defaultImg"
var price: String = "0.0"
var qty: String = "0"
var subtotal: String = "0.00"

var body: some View 
   //.....

这是我找到的一个例子:

import Foundation
import UIKit
import CoreData

class DataManager 
    
    static let shared = DataManager(moc: NSManagedObjectContext.current)
    
    var managedContext: NSManagedObjectContext
    
    private init(moc: NSManagedObjectContext) 
        self.managedContext = moc
    
    
    
    // Delete method
    // remove birthday
    func removeBirthday(id: UUID) 
        let fetchRequest: NSFetchRequest<Birthday> = Birthday.fetchRequest()
        fetchRequest.predicate = NSPredicate.init(format: "id=%@", id.uuidString)
        do 
            let bdays = try self.managedContext.fetch(fetchRequest)
            for bday in bdays 
                self.managedContext.delete(bday)
            
            try self.managedContext.save()
         catch 
          print(error)
        
    
    


extension NSManagedObjectContext 
    static var current: NSManagedObjectContext 
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        return appDelegate.persistentContainer.viewContext
    

【问题讨论】:

【参考方案1】:

在视图模型中创建一个删除给定对象的方法。

类似

func delete(counter: Counter) 
    do 
        viewContext.delete(counter)
        viewContext.save()
     catch 
        // handle error
    


我会稍微更新一下视图代码,让 CounterCell 使用 Counter 属性

struct CounterCell: View 
    @Environment(\.colorScheme) var colorScheme
    @State private var stepperValue = 0
    @StateObject var estimatorData = EstimatorViewModel()

    var counter: Counter

    var body: some View 
   //.....

并相应地更改 ForEach

List 
   ForEach(counters, id: \.self)  counter in
      CounterCell(counter: counter) 
      //...
   

【讨论】:

您好,Joakim 感谢您的回答。目前我只传递 Id 而不是整个计数器对象。我想。我可以重构并发送整个对象,但宁愿通过 id 引用。我今天要再来一次。 我拥有的是一个带有计数器视图的 forEach 我想在计数器视图中调用该方法 我正在努力解决如何将整个对象传递给我的柜台视图,不确定在我的柜台视图中要引用哪种类型的属性 我再次编辑以展示我到目前为止所尝试的内容。 Joakim,再次感谢我的帮助【参考方案2】:

经过上述尝试后,我联系了一位高级开发人员,结果发现这是我在视图模型中访问 managedObjectContext 的方式。在这个过程中,我了解了如何访问在 Persistence 文件中声明的共享 persistenceController,该文件现在包含在 biolerplate SwiftUI Core Data App 中。

这是我的正确方法。

 var viewContext: NSManagedObjectContext  PersistenceController.shared.container.viewContext 

这是我的删除方法

func deleteCounter(id: UUID)  
    let counterRequested: NSFetchRequest<Counter> = Counter.fetchRequest()
    counterRequested.predicate = NSPredicate.init(format: "id=%@", id.uuidString)

    do 
        let savedCounters = try  self.viewContext.fetch(counterRequested)
        
        for counter in savedCounters 
            self.viewContext.delete(counter)
        
        try self.viewContext.save()
     catch 
        print(error)
    

重构

func deleteWindow(id: UUID)  
    if let counter = existingCounter 
        viewContext.delete(counter)
        do 
            try viewContext.save()
         catch 
            print(error)
        
    


【讨论】:

虽然您找到了解决方案很好,但我觉得有点奇怪,您需要获取内存中很可能已经拥有的对象并在视图和/或视图模型中访问。 你如何通过整个柜台? Joakim 再次感谢您的意见 将计数器对象而不是 id(和其他一些属性)作为 CounterCell 中的属性。然后您可以将对象传递给 delete 方法。查看我的更新答案 Joakim 谢谢,我会试一试!

以上是关于按下按钮时 SwiftUI 2.0 iOS 14 Core 数据删除实例的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:允许用户通过按下按钮启用画中画(iOS)

在 swiftUI 中显示来自多个选项的工作表

SwiftUI - 按下按钮时如何更改所有其他按钮的颜色?

SwiftUI:带有onTapGesture的列表单元格内的菜单触发手势

SwiftUI:当我按下按钮时如何打开(App-)电话设置?

在SwiftUI中按下按钮时的随机图像[关闭]