SwiftUI didn't update the view while observedObject changed

175 views Asked by At

I'm doing a login and display data application. While the user login, the data will be displayed correctly. While I logout and login another account, the data supposed to be update by the observedObject which call the function to be reload the data. But while I login into the apps, the home view still display the old data by previous account. I don't know what the problem. I tried many way to solve even I clear the data in class while I Logout, however, the view still didn't update. Looking for help, tq.

struct ContentView: View {
    @EnvironmentObject var authService:AuthService
    var body: some View{
        ZStack{
            if(!authService.signedIn){
                RegisterView()
            }
            else{
                HomePageView()
            }
        }
    }}
struct HomePageView: View {
    @ObservedObject var shopList:ShopJSON = .shared

    var body: some View {
        
        TabView{
            HomePromotionView(shopList: shopList)
                .tabItem {
                        Image(systemName: "house")
                }.tag(1)

            NavigationView{
                BookingView()
            }
                .tabItem {
                    Image(systemName: "calendar")
                }.tag(3)
        }
        .onAppear(perform: ShopJSON.shared.reload) //I try to force reload data.
    }
}
struct HomePromotionView: View {
    @State private var selectedSegment = 0
    @ObservedObject var shopList : ShopJSON

    private let homeSegment = ["PROMOTION", "HISTORY", "MESSAGE"]
    
    var body: some View {
        NavigationView {
            
            VStack {
                ScrollView(.horizontal, showsIndicators: false){
                    
                    HStack{
                        
                        ForEach(shopList.shops){ item in
                            MerchantBar(name:item.name!, icon: item.icon!, id: item.shopID!)
                        }
class ShopJSON: ObservableObject {
    
    @Published var shops = [Shops]()
    @Published var bcsts = [Bcast]()
    @Published var selectedID : Int?
    static let shared = ShopJSON()

    let auth = UserDefaults.standard.string(forKey: "Auth")
    
    private init() {
        load()
    }
    func reload() {
        load()
    }
    func clear() {
        self.shops = [Shops]()
        self.bcsts = [Bcast]()
        self.selectedID = nil
    }
    func load() {
        
        let url = URL(string: "https://12345/shop/")!
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue(self.auth, forHTTPHeaderField: "token")
        request.httpMethod = "GET"
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data else {
                print("No data in response: \(error?.localizedDescription ?? "Unknown error").")
                return
            }
            if let decodedShops = try? JSONDecoder().decode(Json4Swift_Base.self, from: data) {
                DispatchQueue.main.async {
                    self.shops = decodedShops.shops!
                    self.bcsts = decodedShops.bcast!

Logout button

            Text("Sign Out")
                .foregroundColor(Color.gray)
                .onTapGesture {
                    self.authService.signOut()
                    UserDefaults.standard.set(nil, forKey: "Auth")
                    //self.shopList.clear()       //force clean data but view didn't update while login with another account
            }
2

There are 2 answers

0
SAS231 On BEST ANSWER

The problem is I declare the auth token in class. While the user logout the token inside the class didn't update. It will still use the old token to get the result.

The solution is just get the token inside the function instead of declare in the class

Solution:

func load() {
        let url = URL(string: "https://12345/shop/")!
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        let auth = UserDefaults.standard.string(forKey: "Auth")
        request.setValue(auth, forHTTPHeaderField: "token")
        request.httpMethod = "GET"
1
lp1756 On

I have observed the same problem and have worked around it by using EnvironmentObjects instead of ObservedObjects. Not ideal in terms of data encapsulation, but it works for me.