Обновление списка объектов ObservedObject - PullRequest
1 голос
/ 23 октября 2019

Я пытаюсь изучить SwiftUI, я пытаюсь обновить свой список автоматически, как только я вставлю значение. но я получаю большую проблему! мой список не обновляется, когда я использую лист или навигационное представление для вставки данных, он работает только в том случае, если я загружаю данные из моего contentView.

(и я не понимаю, почему класс DataManager имеет ObservableObject и т. д. он работает отлично, если я загружаю данные с 3 текстовыми полями в представлении содержимого)

здесь, под моим проектом: у меня есть модель данных


import Foundation
import Combine

class DataModel: Codable, Identifiable {
    var id: UUID = UUID()
    var airportName : String
    var metar : String
    var taf : String

init(airportName: String, metar: String, taf: String) {
    self.airportName = airportName
    self.metar = metar
    self.taf = taf
}
}

У меня есть DataManager

import SwiftUI
import Combine

class DataManager: ObservableObject {
    let objectWillChange = PassthroughSubject<Void, Never>()


    var storage : [DataModel] = [] {
        willSet {
            objectWillChange.send()
        }
    }
    typealias Storage = [DataModel]

    var filePath : String = ""

    init() { caricaDati() }

    func caricaDati() {
        // creiamo il percorso al file
        filePath = cartellaDocuments() + "test.plist"

        // usiamo NSFileManager per sapere se esiste un file a quel percorso
        if FileManager.default.fileExists(atPath: filePath) {

            // se c'è de-archiviamo il file di testo nell'array
            // serve il blocco do try catch
            do {
                // proviamo a caricare il file dal percorso creato in precedenza
                let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
                // creiamo il decoder
                let decoder = PropertyListDecoder()
                // proviamo a decodificare il file nell'array
                storage = try decoder.decode(Storage.self, from: data)
            } catch {
                // se non ce la fa scriviamo in console l'errore
                debugPrint(error.localizedDescription)
            }

        }
    }

    func salva() {
        objectWillChange.send()
        let encoder = PropertyListEncoder()
        encoder.outputFormat = .xml // impostiamo l'output corretto
        // serve il blocco do try catch
        do {
            // proviamo a codificare l'array
            let data = try encoder.encode(storage)
            // proviamo a salvare l'array codificato nel file
            try data.write(to: URL(fileURLWithPath: filePath))
        } catch {
            // se non ce la fa scriviamo in console l'errore
            debugPrint(error.localizedDescription)
        }
    }

    func newData (nomeApt: String, metar: String, taf: String) {
        let newadd = DataModel(airportName: nomeApt, metar: metar, taf: taf)
        objectWillChange.send()
        storage.append(newadd)
        objectWillChange.send()
        salva()
    }

    func cartellaDocuments() -> String {
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        //print(paths[0])
        return paths[0]
    }
}

Как вы можете видеть, Datamanager - это ObservableObject! и у меня есть простая функция (newData) для добавления значения в хранилище массива.

Теперь моя проблема: если я добавляю данные через 3 текстовых поля в ContentView (), мой список автоматически обновляется без каких-либо проблем.

import SwiftUI

struct ContentView: View {
    @ObservedObject var dm : DataManager
    @State var isAddPresented : Bool = false
    @State var nomeApt : String = ""
    @State var metar : String = ""
    @State var taf : String = ""

    var body: some View {

        VStack {
            Button(action: {
                           self.dm.newData(nomeApt: self.nomeApt, metar: self.metar, taf: self.taf)

                       }) {
                           Text("Add from below")
                       }
            TextField("name apt", text: $nomeApt)
            TextField("name apt", text: $metar)
            TextField("name apt", text: $taf)

            Button(action: {
                self.isAddPresented = true
            }) {
                Text("open view to add")
            }.sheet(isPresented: $isAddPresented) {
                Add(dm: DataManager(), dismissFlag: self.$isAddPresented)
            }
            List(dm.storage) { item in
                HStack {
                    Text(item.airportName)
                    Text(item.metar)
                    Text(item.taf)
                }
            }

        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(dm: DataManager())
    }
}

но если я использую лист для добавления тех же данных, используя ту же функцию, список не обновляется немедленно!

здесь мое второе представление:

import SwiftUI

struct Add: View {
   @ObservedObject var dm : DataManager
    @State var nomeApt : String = ""
    @State var metar : String = ""
    @State var taf : String = ""
    @Binding var dismissFlag: Bool

    var body: some View {
        VStack {
            Spacer()
            TextField("name apt", text: $nomeApt)
            TextField("name apt", text: $metar)
            TextField("name apt", text: $taf)
            Button(action: {
                self.dm.newData(nomeApt: self.nomeApt, metar: self.metar, taf: self.taf)
                self.dismissFlag = false
            }) {
                Text("Aggiungi")
            }
            Spacer()
        }
    }
}

struct Add_Previews: PreviewProvider {
    static var previews: some View {
        Add(dm: DataManager(), dismissFlag: bindBool())
    }
}

func bindBool() -> Binding<Bool> {
    var boolVariable : Bool = true
    let boolVariableBinding : Binding<Bool> = Binding(get: { boolVariable },
                                                      set: { boolVariable = $0 })
    return boolVariableBinding
}

я совершенно не понимаю, почему, если я загружаю данные из представления содержимого, мой список обновляется автоматически, но если я использую навигационный вид представления листа, это не сработает.

заранее спасибо запомощь

1 Ответ

1 голос
/ 24 октября 2019

У меня есть аналогичное рабочее решение для этого.

В вашем случае я бы изменил ваш DataModel следующим образом:

class DataModel: Codable, Identifiable, ObservableObject {
    var id: UUID = UUID()
    @Published var airportName : String = ""
    @Published var metar : String = ""
    @Published var taf : String = ""

    // ...
}

Тогда в вашем DataManager:

class DataManager: ObservableObject {

    @Published var storage : [DataModel] = [] // No longer need forobjectWillChange.send()

    // ...
}

Тогда просто используйте его в своем View:

struct ContentView: View {
    @ObservedObject var dm : DataManager
    // ...

    var body: some View {

        VStack {
            // ...
            List(dm.storage) { item in
                // ...
            }

        }
    }
}

Проблема заключалась в том, что многое изменилось с видео WWDC.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...