更改发布的变量时 SwiftUI 视图不更新
SwiftUI View not updating when Published variable is changed
按下按钮时,我的应用程序正在尝试联系 api 以接收数据。然后将此数据存储在可观察对象内的已发布变量中。出于某种原因,在多次按下打开该视图的按钮之前,该视图不会填充数据。我正在寻找要使用第一次按下按钮时从 api 调用收到的信息更新的视图。我引用的代码如下:
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
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())
}
注意:数据获取器(可观察对象)由内容视图传递给 eventsusercreated 视图
非常感谢任何有关如何正确更新我的视图的帮助
您必须将 data
声明为 @ObservedObject
。
struct EventsUserCreatedView: View {
//...
@ObservedObject var data = DataFetcher()
//...
}
如果您将 DataFetcher
实例作为环境对象传递,则将其声明为 @EnvironmentObject
。
struct EventsUserCreatedView: View {
//...
@EnvironmentObject var data: DataFetcher
//...
}
按下按钮时,我的应用程序正在尝试联系 api 以接收数据。然后将此数据存储在可观察对象内的已发布变量中。出于某种原因,在多次按下打开该视图的按钮之前,该视图不会填充数据。我正在寻找要使用第一次按下按钮时从 api 调用收到的信息更新的视图。我引用的代码如下:
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
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())
}
注意:数据获取器(可观察对象)由内容视图传递给 eventsusercreated 视图
非常感谢任何有关如何正确更新我的视图的帮助
您必须将 data
声明为 @ObservedObject
。
struct EventsUserCreatedView: View {
//...
@ObservedObject var data = DataFetcher()
//...
}
如果您将 DataFetcher
实例作为环境对象传递,则将其声明为 @EnvironmentObject
。
struct EventsUserCreatedView: View {
//...
@EnvironmentObject var data: DataFetcher
//...
}