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)

下面注释的代码不能工作,仍然显示为nil
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。这就是为什么您没有在claimhistory中获得数据的原因。这是两个独立的模型。重构代码,只使用一个AuthViewModel,并将其传递到需要的地方。换句话说,使用:

@StateObject var vm: AuthViewModel = AuthViewModel()

在SignIn和ContentView之前

最新更新