[英]SwiftUI View not updating when Published variable is changed
On a button press, I my app is trying to contact an api to receive data.在按下按钮时,我的应用程序正在尝试联系 api 以接收数据。 This data is then stored in a published variable inside an observable object.
然后将该数据存储在可观察 object 内的已发布变量中。 For some reason, the view doesn't populate with the data until the button that opens that view is press more than once.
出于某种原因,在多次按下打开该视图的按钮之前,该视图不会填充数据。 I am looking for the view to update with the information received from the api call on the first button press.
我正在寻找使用从第一次按下按钮时从 api 调用收到的信息更新的视图。 The code I am referencing is provided below:
我引用的代码如下:
DataFetcher.swift: DataFetcher.swift:
class DataFetcher: ObservableObject{
@Published var dataHasLoaded: Bool = false
@Published var attendeesLoaded: Bool = false
@Published var useresUventsLoaded: Bool = false
@Published var profilesLoaded: Bool = false
@Published var eventsUpdated: Bool = false
@Published var events: [eventdata] = []
@Published var createdEvents: [eventdata] = []
@Published var profile: profiledata?
@Published var atendees: [atendeedata] = []
@Published var IAmAtending: [atendeedata] = []
@Published var eventNames: [eventdata] = []
@Published var profileList: [profiledata] = []
@Published var token: String = UserDefaults.standard.string(forKey: "Token") ?? ""
private var id: Int = 0
func fetchProfile(id: Int){
// events.removeAll()
profileUrl.append("/\(id)")
self.id = id
let url = URL(string: profileUrl)!
var request = URLRequest(url: url)
if let range = profileUrl.range(of: "/\(id)") {
profileUrl.removeSubrange(range)
}
request.httpMethod = "GET"
print(self.token)
request.addValue("Token \(self.token)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request, completionHandler: parseFetchProfileObject)
task.resume()
}
func parseFetchProfileObject(data: Data?, urlResponse: URLResponse?, error: Error?){
guard error == nil else {
print("\(error!)")
return
}
guard let content = data else{
print("No data")
return
}
if let decodedResponse = try? JSONDecoder().decode(profiledata?.self, from: content) {
DispatchQueue.main.async {
self.profile = decodedResponse
self.profileList.append(self.profile!)
}
}
}
func fetchAtendees(id: Int){
// events.removeAll()
atendeeUrl.append("/\(id)")
print(atendeeUrl)
let url = URL(string: atendeeUrl)!
var request = URLRequest(url: url)
if let range = atendeeUrl.range(of:"/\(id)") {
atendeeUrl.removeSubrange(range)
}
request.httpMethod = "GET"
print(self.token)
request.addValue("Token \(self.token)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request, completionHandler: parseFetchAttendeesObject)
task.resume()
}
EventsUserCreatedView.swift事件UserCreatedView.swift
import Foundation
import SwiftUI
import Mapbox
struct EventsUserCreatedView: View {
@Binding var token: String
@State private var pressedEvent: Bool = false
@State private var selectedEvent: Int = 0
@State private var atendees: [atendeedata] = []
@State private var profileList: [profiledata] = []
@State private var showDeleteEventView: Bool = false
var data: DataFetcher
var mapStyle: URL
var body: some View {
ZStack{
//NavigationView {
if self.mapStyle == MGLStyle.darkStyleURL {
List{
ForEach(self.data.createdEvents){ row in
HStack {
Button("\((row.poi)!)") {
print("Display event information")
self.selectedEvent = row.id
self.pressedEvent = true
}
Spacer()
Button("Delete") {
self.showDeleteEventView = true
print("Deletes the event in this row")
}.buttonStyle(BorderlessButtonStyle())
.padding(4)
.background(Color.red)
.cornerRadius(5)
}.foregroundColor(Color.white)
}
}.background(Color.init(red: 0.05, green: 0.05, blue: 0.05))
//if you hit more buttons than there is room for, it'll be scrollable. make some kind of for loop that iterates over events a user is going to and displays it
// }.navigationBarTitle("My Events")
// .navigationViewStyle(StackNavigationViewStyle())
if pressedEvent{
Group{
if self.data.profilesLoaded == true{
//NavigationView {
List{
ForEach(self.data.profileList){ row in
HStack {
Text("\(row.name)")
.foregroundColor(Color.purple)
Spacer()
}
}
}.background(Color.init(red: 0.05, green: 0.05, blue: 0.05))
//if you hit more buttons than there is room for, it'll be scrollable. make some kind of for loop that iterates over events a user is going to and displays it
//}
} else{
Spacer()
Text("Loading Attendees")
Spacer()
}
}.onAppear{
//this can't be done on appear as it won't update when a different
self.data.profileList = []
self.data.atendees = []
DispatchQueue.main.async{
self.data.fetchAtendees(id: self.selectedEvent)
if self.data.profilesLoaded{
self.profileList = self.data.profileList
self.atendees = self.data.atendees
}
}
}
//.navigationBarTitle("My Attendees")
//.navigationViewStyle(StackNavigationViewStyle())
}
NOTE: datafetcher (the observableobject) is passed to eventsusercreated view by the contentview注意:datafetcher(可观察对象)由 contentview 传递给 eventsusercreated 视图
any help on how to update my view properly is much appreciated非常感谢有关如何正确更新我的视图的任何帮助
You've to declare the data
as an @ObservedObject
.您必须将
data
声明为@ObservedObject
。
struct EventsUserCreatedView: View {
//...
@ObservedObject var data = DataFetcher()
//...
}
If you're passing DataFetcher
instance as environment object declare it as @EnvironmentObject
.如果您将
DataFetcher
实例作为环境 object 将其声明为@EnvironmentObject
。
struct EventsUserCreatedView: View {
//...
@EnvironmentObject var data: DataFetcher
//...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.