#swift #core-data #swiftui #ios14 #xcode12
#swift #основные данные #swiftui #ios14 #xcode12
Вопрос:
Я пытаюсь выяснить, как удалить экземпляр объекта core data, вызвав метод в моей 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 для поиска имени объекта «Счетчик»
После пошагового выполнения кода в отладчике это то, что я получаю, когда распечатываю CounterRequested
<NSFetchRequest: 0x282d70380> (сущность: счетчик; предикат: (id == «C4BE9AFF-8A8E-4413-AFA3-AC90850C482E»); Сортировочные дескрипторы: ((null)); тип: 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
}
}
Ответ №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)
//...
}
}
Комментарии:
1. Привет, Йоаким, спасибо за твой ответ. На данный момент я передаю только идентификатор, а не весь объект счетчика. Я полагаю. Я мог бы провести рефакторинг и отправить весь объект целиком, но предпочел бы ссылаться по идентификатору. Сегодня я собираюсь сделать это еще раз.
2. У меня есть forEach с представлением счетчика, я хочу вызвать метод в представлении счетчика
3. Я изо всех сил пытаюсь передать весь объект в мое представление счетчика, не уверенный в том, на какой тип свойства ссылаться в моем представлении счетчика
4. Я снова отредактировал, чтобы показать, что я пробовал до сих пор.
5. Йоаким, еще раз спасибо за помощь, я разобрался
Ответ №2:
После моей попытки, описанной выше, я обратился к старшему разработчику, и оказалось, что именно так я получал доступ к managedObjectContext в моей модели представления. И в процессе я узнал о доступе к общему persistenceController, который объявлен в файле сохранения, который теперь включен в приложение 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)
}
}
}
Комментарии:
1. Хотя хорошо, что вы нашли решение, я нахожу немного странным, что вам нужно извлекать объект, который у вас, скорее всего, уже есть в памяти и к которому у вас есть доступ в вашем представлении и / или модели представления.
2. Как бы вы прошли весь прилавок?
3. Йоаким еще раз спасибо за ваш вклад
4. Имейте объект счетчика вместо идентификатора (и некоторых других свойств) в качестве свойства в CounterCell. Затем вы можете передать объект вместо этого методу удаления. Смотрите мой обновленный ответ
5. Йоаким Спасибо, я попробую!