Swift - 将 json 数据传递给其他视图

Swift - Pass json data to other views

我想弄清楚如何传递我从成功结果中收到的 json 解码数据,以便我可以开始使用它在另一个屏幕视图上显示特定信息。我一直在尝试解决这个问题,但运气不佳,我是 swift 以及应用程序开发的新手,所以这对我来说都是一次学习经历。如果有人可以提供帮助,我们将不胜感激。这是我的一些网络代码

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
                let cookieName = "JSESSIONID"
                if let cookie = HTTPCookieStorage.shared.cookies?.first(where: { [=12=].name == cookieName })  {
                    debugPrint("\(cookieName): \(cookie.value)")
                }
               
                print(response)
            }
            
            // Look into this
            if let data = data {
                results = .success(data)
                
                /*
                // Converts data to readable String
                let responseString = String(data: data, encoding: .utf8) ?? "unable to convert to readable String"
                print("Server Response: \(responseString.description)")
                */
                
            } else if let error = error {
                print("NO this happen")
                results = .failure(error)
                print("Server Error: \(error.localizedDescription)")
            }
            
            DispatchQueue.main.sync {
                self.handleResponse(result: results, completion: completion)
            }
            
        }.resume()
    }
    
   
    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 {
                    completion(.failure(error))
                }
                
                
            case .failure(let error):
                print("This happen")
                completion(.failure(error))
        }
        
    }

这是我用来创建请求的函数

 func signIn(username: String, password: Any, completion: @escaping(Result<LoginResponseData.Root, Error>) -> Void) {
        let params = ["username": "\(username)", "password": "\(password)"]
        
        request(endPoint: .Login, method: .post, parameters: params, completion: completion)
    }

这是我的登录查看码

struct SignIn: View {
    @Binding var userID: String
    @Binding var passcode: String
    @State private var showAlert = false
    @EnvironmentObject var authentication: AuthenticationCheck
    
    var body: some View {
        Button(action: {
            // Remove
            print("Button action")
            
            NetworkService.shared.signIn(username: userID, password: passcode) { (result) in
                switch result {
                case .success(let user):
                    print("This user last name is: \(user.result.login.userName.name.fullName)")
                    
                    authentication.updateValidation(success: true)
                    showAlert = false
                    
                case .failure(let error):
                    print("The error is: \(error.localizedDescription)")
                    showAlert.toggle()

                }
            }
            
            
        }) {
            Text("Sign In")
                .multilineTextAlignment(.center)
                .padding()
        }
        .frame(width: 150.0, height: 43.0)
        .background(/*@START_MENU_TOKEN@*//*@PLACEHOLDER=View@*/Color(red: 0.584, green: 0.655, blue: 0.992)/*@END_MENU_TOKEN@*/)
        .foregroundColor(.white)
        .cornerRadius(20)
        .disabled(userID.isEmpty || passcode.isEmpty)
        .alert(isPresented: $showAlert, content: {
            Alert(title: Text("Invalid Credentials"), message: Text("Either username or password is incorrect. Please try again"), dismissButton: .cancel())
        })
        
    }

这是我的身份验证和应用程序

class AuthenticationCheck: ObservableObject {
    @Published var isValidated = false
    
    func updateValidation(success: Bool) {
        withAnimation {
            isValidated = success
        }
        
    }
    
}

@main
struct SomeApp: App {
    @StateObject var authenticationCheck = AuthenticationCheck()
    
    var body: some Scene {
        WindowGroup {
            if authenticationCheck.isValidated {
                ContentView()
                    .environmentObject(authenticationCheck)
            } else {
                Signin()
                    .environmentObject(authenticationCheck)
            }
            //TestView()
        }
    }
}

这是您的代码的简化版本

class AuthViewModel: ObservableObject {
    // I don't have your Model info
    //You can have an empty object of your model or you can make it an optional, etc
    @Published var user: YourModel? = nil
    @Published var alert: CustomAlert? = nil
    let networkService: NetworkService = NetworkService.shared
    var authentication: AuthenticationCheck? = nil
    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)")
                //Assign you value to the Published variable here
                self.user = user
                self.authentication?.updateValidation(success: true)
                self.alert = CustomAlert(title: "Success", message: "You logged in")
                
            case .failure(let error):
                print("The error is: \(error)")
                //Reset the variable
                self.user = nil
                self.authentication?.updateValidation(success: false)
                //You can pass a better message to the user like this
                self.alert = CustomAlert(title: "Invalid Credentials", message: "\(error)")

            }
        }
    }
    
    func logout() {
        self.user = nil
        authentication?.updateValidation(success: false)
        self.alert = CustomAlert(title: "See you later", message: "You logged out")
    }
}
class AuthenticationCheck: ObservableObject {
    @Published var isValidated = false
    func updateValidation(success: Bool) {
        withAnimation {
            isValidated = success
        }
    }
}
struct SampleNetworkView: View {
    @StateObject var vm: AuthViewModel = AuthViewModel()
    @StateObject var authentication: AuthenticationCheck = AuthenticationCheck()
    @State var username: String = ""
    @State var password: String = ""
    var body: some View {
        NavigationView{
            switch authentication.isValidated{
            case true:
                VStack{
                Text("Signed In - you are now in the content view")
                    .toolbar(content: {
                        Button("log out", action: {
                            vm.logout()
                        })
                    })
                }
            case false:
                VStack{
                    TextField("username", text: $username).textFieldStyle(RoundedBorderTextFieldStyle())
                    SecureField("password", text: $password).textFieldStyle(RoundedBorderTextFieldStyle())
                    Button("sign in", action: {
                        vm.signIn(username: username, password: password)
                    }).disabled(username.isEmpty || password.isEmpty)
                }
            }
        
        }
        //Inject the StateObjects to the navigation view so you can access the variables
        .environmentObject(authentication)
        .environmentObject(vm)
        //Create a shared Alert for the ViewModel
        .alert(item: $vm.alert, content: { customAlert in
            Alert(title: Text(customAlert.title), message: Text(customAlert.message), dismissButton: .default(Text("ok")))
        })
        //Pass the authentication to the ViewModel so you can pass info
        .onAppear(perform: {
            vm.authentication = authentication
        })
    }
}

struct SampleNetworkView_Previews: PreviewProvider {
    static var previews: some View {
        SampleNetworkView()
    }
}
//This assists in creating a shared alert
struct CustomAlert : Identifiable {
    let id: UUID = UUID()
    var title: String
    var message: String
}