在URLSession中观察环境对象

时间:2020-03-10 08:38:30

标签: ios swift swiftui

我试图在URLSession中更新environmentObject。

我的登录视图。

struct LoginView: View {
    @EnvironmentObject var env: Env

    ...

    var body: some View {
        Group {
            if env.isLogin {    // 2    but the env.isLogin is still false
                UserView()
            } else {
                VStack {
                    ...
                    Button(action: {
                        self.login(name: self.name, pass: self.pass)
                    }) {
                        Text("Login")
                    }

                    Text("isLogin: \(String(env.isLogin))")
                }
                .padding()
            }
        }
    }

    func login(name: String, pass: String) {
        ...

        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
                    DispatchQueue.main.async {
                        ...
                        if ... {
                            self.env.isLogin = true
                            print(self.system.isLogin)    // 1   output true
                        }
                    }

                    return
                }
            }

            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
        }.resume()
    }
}

我的开始视图。

class Env: ObservableObject {
    @Published var isLogin: Bool = false
}

struct ContentView: View {
    let env = Env()

    var body: some View {
        VStack {
            if env.isLogin {
                UserView()
            } else {
                LoginView()
            }
        }
        .environmentObject(env)
    }
}

我可以确保在位置1处将isLogin更新为true,但是env的相关属性在位置2处不会对其进行响应。

分辨率

我创建另一个视图LoginToOtherView,并将其替换为ContentView。

struct LoginToOtherView: View {
    @EnvironmentObject var env: Env

    var body: some View {
        Group {
            if env.isLogin {
                UserView()
            }
        }
    }
}

// and in place 2.
if env.isLogin {
    LoginToOtherView()
}

1 个答案:

答案 0 :(得分:1)

我简化了向可测试模块提供的代码快照后,一切工作正常。经过Xcode 11.4beta2测试。

完整的可测试模块:

class Env: ObservableObject {
    @Published var isLogin: Bool = false
}

struct LoginViewEnv: View {
    @EnvironmentObject var env: Env
    var body: some View {
        Group {
            if env.isLogin {
                Text("UserView") // << shown in 2 secs after button click
            } else {
                VStack {
                    Button(action: {
                        self.login(name: "name", pass: "pass")
                    }) {
                        Text("Login")
                    }

                    Text("isLogin: \(String(env.isLogin))")
                }
                .padding()
            }
        }
    }

    func login(name: String, pass: String) {
        // simulate async login
        DispatchQueue.global(qos: .background).asyncAfter(deadline: .now( ) + 2) {
            DispatchQueue.main.async {
                self.env.isLogin = true
                print(self.env.isLogin)
            }
        }
    }
}

struct TestVStackEnv: View {
    let env = Env()

    var body: some View {
        VStack {
            if env.isLogin {
                Text("UserView")
            } else {
                LoginViewEnv()
            }
        }
        .environmentObject(env)
    }
}

struct TestVStackEnv_Previews: PreviewProvider {
    static var previews: some View {
        TestVStackEnv()
    }
}