在 app/preview 重新打开之前视图不会更新

View doesn't update until app/preview is re-opened

问题:如何在不重启 app/preview 的情况下从 Login() 返回到 Home()?我有一种感觉,它与变量不是 @State 有关,但我不知道如何将 @State 添加到全局变量。

这是我的代码:

import SwiftUI

var isLoggedIn:Bool {
    get {
        // Get the standard UserDefaults as "defaults"
        let defaults = UserDefaults.standard

        // Makes the "welcomeString" variable whatever the saved value for "welcome_string" is
        return defaults.bool(forKey: "isLoggedIn")
    }
    set (newValue) {
        // Get the standard UserDefaults as "defaults"
        let defaults = UserDefaults.standard

        // Saves what the "welcomeString" variable was just set to as the saved value for "welcome_string"
        defaults.set(newValue, forKey: "isLoggedIn")
    }
}


struct ContentView: View {
  var body: some View {
    if isLoggedIn {
    Home()
    } else {
      Login()
    }
  }
}

struct Login: View {
  var body: some View {
    Button(action: {
      isLoggedIn = true
    }) {
      Text("Click to login")
    }
  }
}

struct Home: View {

  private enum Tab: Hashable {
    case schedule
    case messaging
    case home
    case resources
    case settings
  }

  @State private var selectedTab: Tab = .home

  var body: some View {
    VStack {
      TabView(selection: $selectedTab) {
        One()
          .tag(Tab.home)
          .tabItem {
            Label("One", systemImage: "note")
          }
        Two()
          .tag(Tab.home)
          .tabItem {
            Label("Two", systemImage: "note")
          }
        Three()
          .tag(Tab.home)
          .tabItem {
            Label("Three", systemImage: "note")
          }
        Four()
          .tag(Tab.home)
          .tabItem {
            Label("Four", systemImage: "note")
          }
      }
    }
  }
}

struct One: View {
  var body: some View {
    Text("One")
  }
}

struct Two: View {
  var body: some View {
    Text("Two")
  }
}

struct Three: View {
  var body: some View {
    Text("Three")
  }
}

struct Four: View {
  var body: some View {
    Button(action: {
      isLoggedIn = false
    }) {
      Text("Logout")
    }
  }
}


struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

我不知道你为什么会遇到这个简单的问题,如果变量没有用 SwiftUI 的工作方式包装,你就不能依赖变量的值更新,这里是第一种方法,具体取决于你的方法问题,不要忘记模拟器在 UserDefaults 下无法正常工作,因此它可能无法正常工作,然后尝试在真实设备上使用:

struct ContentView: View {
    
    @State private var isLoggedIn: Bool = { return UserDefaults.standard.bool(forKey: "isLoggedIn") }()
    
    var body: some View {
        
        if (isLoggedIn) {
            Home(isLoggedIn: $isLoggedIn)
        }
        else {
            Login(isLoggedIn: $isLoggedIn)
        }  
    }
}

func updateLog(_ newValue: Bool) { UserDefaults.standard.set(newValue, forKey: "isLoggedIn") }


struct Login: View {
    
    @Binding var isLoggedIn: Bool
    var body: some View {
        Button("Tap to login") { isLoggedIn = true; updateLog(true) }
    }
}

struct Home: View {
    
    private enum Tab: Hashable {
        case schedule
        case messaging
        case home
        case resources
        case settings
    }
    
    @State private var selectedTab: Tab = .home
    @Binding var isLoggedIn: Bool
    
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                One()
                    .tag(Tab.home)
                    .tabItem {
                        Label("One", systemImage: "note")
                    }
                Two()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Two", systemImage: "note")
                    }
                Three()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Three", systemImage: "note")
                    }
                Four(isLoggedIn: $isLoggedIn)
                    .tag(Tab.home)
                    .tabItem {
                        Label("Four", systemImage: "note")
                    }
            }
        }
    }
}

struct One: View {
    var body: some View {
        Text("One")
    }
}

struct Two: View {
    var body: some View {
        Text("Two")
    }
}

struct Three: View {
    var body: some View {
        Text("Three")
    }
}

struct Four: View {
    @Binding var isLoggedIn: Bool
    var body: some View {
        Button("Logout") { isLoggedIn = false; updateLog(false) }
    }
}

第二种方式:

struct ContentView: View {
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    var body: some View {
        
        if (isLoggedIn) {
            Home()
        }
        else {
            Login()
        }
    }
}

struct Login: View {
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    var body: some View {
        Button("Tap to login") { isLoggedIn = true }
    }
}

struct Home: View {
    
    private enum Tab: Hashable {
        case schedule
        case messaging
        case home
        case resources
        case settings
    }
    
    @State private var selectedTab: Tab = .home
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                One()
                    .tag(Tab.home)
                    .tabItem {
                        Label("One", systemImage: "note")
                    }
                Two()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Two", systemImage: "note")
                    }
                Three()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Three", systemImage: "note")
                    }
                Four()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Four", systemImage: "note")
                    }
            }
        }
    }
}

struct One: View {
    var body: some View {
        Text("One")
    }
}

struct Two: View {
    var body: some View {
        Text("Two")
    }
}

struct Three: View {
    var body: some View {
        Text("Three")
    }
}

struct Four: View {
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    var body: some View {
        Button("Logout") { isLoggedIn = false }
    }
}