arrays - ObservedObject 列表更新
问题描述
我正在尝试学习 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
}
}
我有一个数据管理器
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)来将值添加到数组存储中。
现在我的问题是:如果我通过 ContentView() 中的 3 个文本字段添加数据,我的列表会自动更新,完全没有问题
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
}
我完全不明白的是,为什么如果我从内容视图加载数据,我的列表会自动更新,但如果我使用工作表视图的导航视图,这不起作用。
在此先感谢您的帮助
解决方案
我有一个类似的工作解决方案。
在你的情况下,我会修改你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 视频以来发生了很多变化。
推荐阅读
- gatsby - 如何安装“gatsby-plugin-sharp”插件
- java - 获取特定键的循环占位符引用错误
- c - Codechef 问题的运行时错误:修改的斐波那契数列。有什么错误?
- java - 如何在java中获取系统日期和时间格式?
- python-3.x - Keras 2.2.4 错误:AttributeError:“NoneType”对象没有属性“inbound_nodes”
- kubernetes - Kubernetes API 服务器和 Kubelet 通信
- ruby - 如何在 ruby 中将 JSON/字符串属性转换为具有精度和比例的十进制数
- python - 将列表中的两个连续项目替换为一项
- swift - 如何实现堆栈视图?
- swift - 为什么 swift 中的中缀运算符不起作用?