swift - Swiftui - 无法访问环境对象
问题描述
我正在做一个项目,我对服务器进行网络调用并根据我进行的调用类型获取不同的数据。我面临的问题是从我的数据中访问变量,这些变量被解码为一个结构以显示在我的视图上。该结构一开始是 nil,但在用户登录时会在呈现内容视图之前进行解码。我的 json 能够毫无问题地解码。如果有人对我如何优化我的代码以使其工作有任何建议,那将不胜感激。我是 swift 新手,所以这对我来说都是一次学习经历
这是我的一些网络代码
struct NetworkService {
static let shared = NetworkService()
// Singleton that Only allows one instance of this class
private init() {}
func request<T: Decodable>(endPoint: EndPoint, method: Method, parameters: [String: Any]? = nil, completion: @escaping(Result<T, Error>) -> Void) {
// Creates a urlRequest
guard let request = createRequest(endPoint: endPoint, method: method, parameters: parameters) else {
completion(.failure(AppError.invalidUrl))
return
}
let session = URLSession.shared
session.dataTask(with: request) { data, response, error in
var results: Result<Data, Error>?
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
completion(.failure(AppError.badStatusCode))
return
}
if let response = response {
/*
// Gets the JSESSIONID - Remove?
let cookieName = "JSESSIONID"
if let cookie = HTTPCookieStorage.shared.cookies?.first(where: { $0.name == cookieName }) {
debugPrint("\(cookieName): \(cookie.value)")
}*/
print(response)
}
if let data = data {
results = .success(data)
} else if let error = error {
results = .failure(error)
print("Server Error: \(error.localizedDescription)")
}
DispatchQueue.main.async {
self.handleResponse(result: results, completion: completion)
}
}.resume()
}
/// Helper function that decodes JSON data response from server
private func handleResponse<T: Decodable>(result: Result<Data, Error>?, completion: (Result<T, Error>) -> Void) {
guard let result = result else {
completion(.failure(AppError.unknownError))
return
}
switch result {
case .success(let data):
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print("Server JsonObject response: \(json)")
} catch {
completion(.failure(AppError.errorDecoding))
}
let decoder = JSONDecoder()
// Decodes that json data
do {
let json = try decoder.decode(T.self, from: data)
completion(.success(json))
} catch {
print("This caused the problem")
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
这是我的 AuthViewModel,它作为解码我的 json 数据的真实来源
class AuthViewModel: ObservableObject {
@Published var user: LoginResponseData.Root? = nil
@Published var alert: CustomAlert? = nil
@Published var claimHistroy: ClaimStruct? = nil
var authentication: AuthenticationCheck? = nil
var showLoader = false
let networkService: NetworkService = NetworkService.shared
func signIn(username: String, password: String) {
networkService.signIn(username: username, password: password) { (result) in
switch result {
case .success(let user):
print("This user last name is: \(user.result.login.userName.name.fullName)")
self.user = user
self.authentication?.updateValidation(success: true)
// Calls method
self.profileSessionMember()
case .failure(let error):
print("The error is: \(error.localizedDescription)")
//Reset the variable
//self.user = nil
self.authentication?.updateValidation(success: false)
// Pass a message to the user
self.alert = CustomAlert(title: "Invalid Credentials", message: "Either username or password is incorrect. Please try again")
}
}
}
/// Gets the Search Savings Amouny from decoded struct
func profileSessionMember() {
networkService.profileSessionMember { result in
switch result {
case .success(let userHistory):
// Sets the claimHistory
self.claimHistroy = userHistory
print("This happened")
print(self.claimHistroy?.result.member.yearToDateSearchSavingsAmount ?? "didnt work")
case .failure(let error):
print(error)
}
}
}
func logout() {
self.user = nil
authentication?.updateValidation(success: false)
}
//This assists in creating a shared alert
struct CustomAlert : Identifiable {
let id: UUID = UUID()
var title: String
var message: String
}
} // End of AuthViewModel
class AuthenticationCheck: ObservableObject {
@Published var isValidated = false
func updateValidation(success: Bool) {
withAnimation {
isValidated = success
}
}
}
这是我将对象传递给环境的一些内容视图
struct ContentView: View {
@StateObject var test: AuthViewModel = AuthViewModel()
var body: some View {
TabView {
Home()
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
Search()
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "magnifyingglass")
Text("Search")
}
Text("Profile Page")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "person.fill")
Text("Profile")
}
}//tab view ends here
.environmentObject(test)
此代码不起作用但仍显示为 nill 在下面注释
struct SearchHistory: View {
@EnvironmentObject var vm: AuthViewModel
var body: some View {
VStack {
Text("BASED ON YOUR SEARCH HISTORY")
.font(.title3)
.fontWeight(.heavy)
.foregroundColor(Color(red: 0.584, green: 0.655, blue: 0.992, opacity: 100.0))
.multilineTextAlignment(.center)
.padding()
HStack {
Image(systemName: "dollarsign.circle")
.resizable()
.frame(width: 43.0, height: 44.0)
.aspectRatio(contentMode: .fill)
.padding()
VStack{
Text("Total")
.multilineTextAlignment(.center)
Text("Amount")
.multilineTextAlignment(.center)
// Display Search Saving
// This shows up as nil
Text(String(describing: vm.claimHistroy?.result.member.yearToDateSearchSavingsAmount))
这是我的登录被调用的地方
struct SignIn: View {
@StateObject var vm: AuthViewModel = AuthViewModel()
@EnvironmentObject var authentication: AuthenticationCheck
@Binding var userID: String
@Binding var passcode: String
var body: some View {
Button(action: {
// Remove
print("Button action")
vm.signIn(username: userID, password: passcode)
}) {
Text("Sign In")
.multilineTextAlignment(.center)
.padding()
}
.frame(width: 150.0, height: 43.0)
解决方案
在 SignIn 中您有一个 AuthViewModel,在 ContentView 中您有另一个 AuthViewModel。这就是为什么您没有在 claimHistroy 中获取数据的原因。这是两个独立的模型。重组您的代码以仅使用一个 AuthViewModel,并将其传递到您需要的地方。换句话说,使用:
@StateObject var vm: AuthViewModel = AuthViewModel()
在登录和内容视图之前。
推荐阅读
- c++ - 删除的功能,不能将一条记录重写为另一条记录,对象
- xamarin.forms - 无法在 UWP 应用程序中发现蓝牙设备,但在 WPF 应用程序中工作
- react-native - 如何在 React Native 中的身份验证状态更改时更改路由
- python - PyCharm IDE:“import @”代码有效,但“from @import @”无效
- javascript - 使用 Jest 模拟节点模块时出现 TypeError
- mysql - 约束一个值在 mySQL 的同一列中最多重复 3 次
- laravel - 下载页面的视图和控制器
- r - 计算大于 0 的值并计算有多少与一行中的模式匹配(在 R 中)
- arrays - 如何使用 Angular 2+ 访问图像中的数组元素
- reactjs - 试图用道具改变广场的可见性