SwiftUI 2.0 iOS 14 Экземпляр удаления основных данных при нажатии кнопки

Я пытаюсь понять, как удалить экземпляр основного объекта данных, вызвав метод в моей ViewModel. Мне удалось получить идентификатор экземпляра моего метода, возможно, я просто борюсь с синтаксисом. Я использую 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 не является допустимым NSPersistentStoreCoordinator для поиска имени объекта 'Counter'

После выполнения кода в отладчике это то, что я получаю, когда распечатываю CounterRequested.

‹NSFetchRequest: 0x282d70380› (entity: Counter; предикат: (id == C4BE9AFF-8A8E-4413-AFA3-AC90850C482E); sortDescriptors: ((null)); type: NSManagedObjectResultType;)

идентификаторы действительно совпадают

Затем он вылетает в первой строке в блоке do

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
    }
}

person Mike Haslam    schedule 11.01.2021    source источник


Ответы (2)


Создайте в своей модели представления метод, который удаляет заданный объект.

Что-то вроде

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) 
      //...
   }

}

person Joakim Danielson    schedule 11.01.2021
comment
Привет, Йоаким, спасибо за ответ. На данный момент я передаю только идентификатор, а не весь объект счетчика. Я предполагаю. Я мог бы провести рефакторинг и отправить весь объект, но предпочел бы ссылаться по идентификатору. Я собираюсь пойти еще раз сегодня. - person Mike Haslam; 11.01.2021
comment
У меня есть forEach со счетчиком, я хочу вызвать метод в счетчике - person Mike Haslam; 11.01.2021
comment
Я борюсь с тем, как передать весь объект моему счетчику, не зная, на какой тип свойства ссылаться в моем счетчике - person Mike Haslam; 11.01.2021
comment
Я отредактировал свой вопрос - person Mike Haslam; 11.01.2021
comment
Я снова отредактировал, чтобы показать, что я пробовал до сих пор. - person Mike Haslam; 11.01.2021
comment
Joakim, еще раз спасибо за помощь разобрался - person Mike Haslam; 12.01.2021

После попытки, описанной выше, я обратился к старшему разработчику, и оказалось, что это был способ доступа к managedObjectContext в моей модели представления. И в процессе я узнал о доступе к общему persistenceController, который объявлен в файле Persistence, который теперь включен в приложение Biolerplate SwiftUI Core Data.

Вот правильный способ в моем случае.

 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)
        }
    }

}
person Mike Haslam    schedule 11.01.2021
comment
Хотя хорошо, что вы нашли решение, мне кажется немного странным, что вам нужно получить объект, который, скорее всего, уже есть в памяти и к которому у вас есть доступ в вашем представлении и / или модели представления. - person Joakim Danielson; 12.01.2021
comment
Как бы вы прошли весь счетчик? - person Mike Haslam; 14.01.2021
comment
Йоаким Еще раз спасибо за ваш вклад - person Mike Haslam; 14.01.2021
comment
Сделайте объект счетчика вместо идентификатора (и некоторых других свойств) в качестве свойства в CounterCell. Затем вы можете передать объект методу удаления. Смотрите мой обновленный ответ - person Joakim Danielson; 14.01.2021
comment
Йоаким Спасибо, я попробую! - person Mike Haslam; 14.01.2021