简体   繁体   English

SwiftUI 发布变量更改时视图未更新

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM