SwiftUI View не обновляется при изменении опубликованной переменной - PullRequest
0 голосов
/ 06 августа 2020

При нажатии кнопки мое приложение пытается связаться с 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 с помощью contentview

любая помощь в том, как правильно обновить мое представление, очень ценится

1 Ответ

3 голосов
/ 06 августа 2020

Вы должны объявить data как @ObservedObject.

struct EventsUserCreatedView: View {
    //...
    @ObservedObject var data = DataFetcher()
    //...
}

Если вы передаете экземпляр DataFetcher в качестве объекта среды, объявите его как @EnvironmentObject.

struct EventsUserCreatedView: View {
    //...
    @EnvironmentObject var data: DataFetcher
    //...
}
...