SwiftUI не обновил представление при изменении observedObject

#swiftui #observedobject #zstack

#swiftui #observedobject #zstack

Вопрос:

Я делаю приложение для входа в систему и отображения данных. При входе пользователя в систему данные будут отображаться правильно. Когда я выхожу из системы и вхожу в другую учетную запись, данные должны обновляться observedObject, который вызывает функцию для перезагрузки данных. Но пока я вхожу в приложения, в главном окне по-прежнему отображаются старые данные по предыдущей учетной записи. Я не знаю, в чем проблема. Я перепробовал много способов решения, даже если я очищаю данные в классе при выходе из системы, однако представление по-прежнему не обновлялось. Ищу помощь, 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!

  

Кнопка выхода из системы

             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
            }
  

Ответ №1:

Я наблюдал ту же проблему и обошел ее, используя EnvironmentObjects вместо ObservedObjects. Не идеально с точки зрения инкапсуляции данных, но для меня это работает.

Комментарии:

1. Я все еще нахожу правильное решение для его решения. EnvironmentObjects может решить проблему, но это действительно плохая идея

Ответ №2:

Проблема в том, что я объявляю токен аутентификации в классе. При выходе пользователя из системы токен внутри класса не обновлялся. Он по-прежнему будет использовать старый токен для получения результата.

Решение просто получить токен внутри функции вместо объявления в классе

Решение:

 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"