1

On a button press, I my app is trying to contact an api to receive data. This data is then stored in a published variable inside an observable 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. The code I am referencing is provided below:

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())
                }

NOTE: datafetcher (the observableobject) is passed to eventsusercreated view by the contentview

any help on how to update my view properly is much appreciated

1 Answer 1

5

You've to declare the data as an @ObservedObject.

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

If you're passing DataFetcher instance as environment object declare it as @EnvironmentObject.

struct EventsUserCreatedView: View {
    //...
    @EnvironmentObject var data: DataFetcher
    //...
}
Sign up to request clarification or add additional context in comments.

1 Comment

I am still having this issue in iOS 15.5

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.