#swift #swiftui
Вопрос:
Я изо всех сил пытаюсь научиться использовать основные данные и заставить их принудительно синхронизировать представление, используя @State. В основном я пытаюсь создать простое в использовании приложение, чтобы узнать, как все это работает вместе. Я могу добавить новый элемент в основные данные, но каким-то образом представление не обновляет список элементов в режиме реального времени, мне нужно остановить предварительный просмотр, а затем перестроить, чтобы мой новый элемент появился в списке.
Может кто-нибудь взглянуть на мой код, чтобы понять, что не так?
Я разделил свой код на 4 файла:
import Foundation
import CoreData
import UIKit
class CoreDataStorage {
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "StoriesFromFallacya")
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Unable to load persistent stores: (error)")
}
}
return container
}()
var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
func fetchTaskList() -> [Dump] {
let dumpList: [Dump]
let fetchRequest: NSFetchRequest<CDDump> = CDDump.fetchRequest()
if let rawDumPlist = try? context.fetch(fetchRequest){
dumpList = rawDumPlist.compactMap({(rawDump:CDDump) -> Dump? in
Dump(fromCoreDataObject: rawDump)
})
}else {
dumpList = []
}
return dumpList
}
func addNewDump(dump: Dump){
let newDump = CDDump(context: context)
newDump.id = dump.id
newDump.name = dump.name
saveData()
}
func fetchCDDump(withId dumpId: UUID) -> CDDump?{
let fetchRequest: NSFetchRequest<CDDump> = CDDump.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "id == %@", dumpId as CVarArg)
fetchRequest.fetchLimit = 1
let fetchResult = try? context.fetch(fetchRequest)
return fetchResult?.first
}
private func saveData(){
if context.hasChanges {
do {
try context.save()
}catch {
print("Erreur pendant la sauvegarde CoreData: (error)")
}
}
}
func deleteDump(dumpID:UUID){
if let dumpFound = fetchCDDump(withId: dumpID){
self.context.delete(dumpFound)
saveData()
}else {
print("Pas trouvé")
}
}
}
extension Dump {
init?(fromCoreDataObject coreDataObject: CDDump){
guard let id = coreDataObject.id, let name = coreDataObject.name else {
return nil
}
self.id = id
self.name = name
}
}
- DumpManager
import Foundation
import SwiftUI
class DumpManager: ObservableObject {
let storage: CoreDataStorage = CoreDataStorage()
@Published var dumpList: [Dump]
init(){
dumpList = storage.fetchTaskList()
}
@discardableResult
func addDump(dumpName: String) -> Dump {
let newDump = Dump(name: dumpName)
dumpList.append(newDump)
storage.addNewDump(dump: newDump)
return newDump
}
func deleteDump(withID dumpID:UUID) {
if let indexDump = dumpList.firstIndex(where: {
(dump) -> Bool in
dump.id == dumpID
}) {
dumpList.remove(at: indexDump)
storage.deleteDump(dumpID: dumpID)
}
}
}
- BrainDumpView
import SwiftUI
import CoreData
struct BrainDumpView: View {
// @ObservedObject var dumpManager: DumpManager = DumpManager()
@State var theFuckingList = DumpManager().dumpList
@State var taskManager = DumpManager()
@State private var showingAddDumpView: Bool = false
// @State var newDumpName: String
var body: some View {
NavigationView {
VStack {
VStack(alignment: HorizontalAlignment.leading){
List{
ForEach(taskManager.dumpList) { dump in
Text(dump.name)
}
.onDelete(perform: deleteDump)
.onTapGesture {
updateDump()
}
}
Spacer()
}
}
.navigationBarTitle(Text("Brain Dumps"))
.navigationBarItems(trailing:
Button(action:
showingAddDump
) {
Image(systemName: "plus")
.font(.largeTitle)
}
)
}
.sheet(isPresented: $showingAddDumpView, content: {
NewDumpView(newDumpName: "", dumpList: $taskManager.dumpList)
})
}
func showingAddDump() {
showingAddDumpView.toggle()
}
// func createNewDump() {
// if newDumpName.count > 0 {
// dumpManager.addDump(dumpName: newDumpName)
// }
// newDumpName = ""
// }
func deleteDump(offsets: IndexSet){
taskManager.deleteDump(withID: taskManager.dumpList[offsets[offsets.startIndex]].id)
}
}
func updateDump(){
}
struct BrainDumpView_Previews: PreviewProvider {
static var previews: some View {
BrainDumpView()
}
}
- NewDumpView
import SwiftUI
struct NewDumpView: View {
@Environment(.presentationMode) var presentationMode
@ObservedObject var dumpManager: DumpManager = DumpManager()
@State var taskManager = DumpManager()
@State var newDumpName: String
@Binding var dumpList: [Dump]
var body: some View {
NavigationView {
VStack{
Spacer()
TextField("Dump", text: $newDumpName, onCommit: createNewDump)
.padding()
.background(Color(UIColor.tertiarySystemFill))
.cornerRadius(9)
.font(.system(size: 24, weight: .bold, design: .default))
.navigationBarTitle("New Dump", displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "xmark")
}
)
Button(action: {
self.presentationMode.wrappedValue.dismiss()
createNewDump()
}) {
Text("Save")
}
}
}
.padding()
.navigationViewStyle(StackNavigationViewStyle())
}
func createNewDump() {
if newDumpName.count > 0 {
taskManager.addDump(dumpName: newDumpName)
}
newDumpName = ""
self.presentationMode.wrappedValue.dismiss()
}
}
Заранее большое спасибо, я уже несколько дней борюсь с этим :/
Комментарии:
1. Вы не наблюдаете за хранилищем или основными объектами данных. Я предлагаю вам просмотреть пример кода, предоставляемый при создании проекта. Вы пытаетесь применить MVC в SwiftUI, не понимая, как работает SwiftUI, наблюдение является ключевым. У вас в аренде 5 экземпляров вашего менеджера, ни один из них не знает, что делает другой. Вместо того, чтобы форсировать события, попробуйте изучить основные концепции с помощью учебных пособий Apple SwiftUI