POST 请求后在 swift 模型中访问值的问题

Posted

技术标签:

【中文标题】POST 请求后在 swift 模型中访问值的问题【英文标题】:Issues with accessing values in swift model after POST request 【发布时间】:2019-07-19 10:55:12 【问题描述】:

我是一个完全的 swift 初学者。在遵循在线教程后,我成功地向我的 API 服务发出 POST 请求,但是,我现在希望将 LoginResponse 模型类中的值返回到 SwiftUI 视图结构,以便我可以更改状态变量的值.

模型类

// MARK: - LoginResponse
class LoginResponse: Codable 
    let message, oauthToken, status: String
    let userData: [UserDatum]

    enum CodingKeys: String, CodingKey 
        case message
        case oauthToken = "oauth_token"
        case status
        case userData = "user_data"
    

    init(message: String, oauthToken: String, status: String, userData: [UserDatum]) 
        self.message = message
        self.oauthToken = oauthToken
        self.status = status
        self.userData = userData
    


// MARK: - UserDatum
class UserDatum: Codable 
    let emailAddress, firstName, lastName, phoneNumber: String
    let userID: String
    let userOnboardStage: Int

    enum CodingKeys: String, CodingKey 
        case emailAddress = "email_address"
        case firstName = "first_name"
        case lastName = "last_name"
        case phoneNumber = "phone_number"
        case userID = "user_id"
        case userOnboardStage = "user_onboard_stage"
    

    init(emailAddress: String, firstName: String, lastName: String, phoneNumber: String, userID: String, userOnboardStage: Int) 
        self.emailAddress = emailAddress
        self.firstName = firstName
        self.lastName = lastName
        self.phoneNumber = phoneNumber
        self.userID = userID
        self.userOnboardStage = userOnboardStage
    

网络服务类

enum APIError:Error

    case responseProblem
    case decodingProblem
    case encodingProblem



struct APIRequest 

    let resourceURL: URL
    let parameters: Dictionary<String, String>

    init(endpoint: String, email: String, password: String)

        let resourceString = "https://someurl/\(endpoint)"
        guard let resourceURL = URL(string: resourceString) else fatalError()

        self.resourceURL = resourceURL

        var parameters = Dictionary<String, String>()

        parameters = ["email_address":email,
                      "password":password,
                      "user_device_token":"",
                      "client_id":"",
                      "client_secret":""]

        self.parameters = parameters

    


    func save(_ loginResponseToSave:LoginResponse, completion: @escaping(Result<LoginResponse, APIError>) -> Void)


        do 

            var urlRequest = URLRequest(url : resourceURL)

            urlRequest.httpMethod = "POST"
            urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
            urlRequest.httpBody = try JSONEncoder().encode(self.parameters)

            let dataTask = URLSession.shared.dataTask(with: urlRequest) data , response, _ in

                guard let httpResponse  = response as? HTTPURLResponse, httpResponse.statusCode == 200, let jsonData = data else 

                    completion(.failure(.responseProblem))
                    return
                

                do 

                    let loginData = try JSONDecoder().decode(LoginResponse.self, from: jsonData)

                    completion(.success(loginData))


                catch

                    completion(.failure(.decodingProblem))
                
            
            dataTask.resume()

        catch

            completion(.failure(.encodingProblem))

        

    


登录控制器

class Login 


    // This function is called from the view
    func loginUser(email:String, password:String) -> Bool


let loginRequest = LoginResponse(message: "", oauthToken: "", status: "", userData: [])

        let postRequest = APIRequest(endpoint: "login_buyer", email: email, password: password)




        postRequest.save(loginRequest, completion: result in
            switch result
            case .success(let status):

                print(status.status) < ---- I want to access this value outside of this scope 



            case .failure(let error):

                print(error)


            
        )


       /// I want to return it here

        return status.status <---- for example

    


我希望能够访问保存在 LoginResponse 模型中的值,但是当我尝试访问它时,我得到了一个 nil 值??

【问题讨论】:

Result 又从何而来?我以前见过……不久前 【参考方案1】:

当您调用 API 时,您正在执行异步请求,这将在后台运行,并且函数将在完成之前返回,因此您需要像在其他地方一样使用完成处理程序......或者使用返回并在范围内时的数据。

您很可能只需像这样更新您的方法:

 func loginUser(email:String, password:String, completion: (LoginResponse?) -> Void)

然后

 switch result 
     case .success(let loginResponse):
         print(loginResponse)
         completion(loginResponse) 
     case .failure(let error):
         print(error)
         completion(nil)
 

当你调用 loginUser 时:

loginUser(email: "email", password: "pwd")  response in 
    guard let loginResponse = response else  return 

    // do something here with the response

【讨论】:

感谢@Scriptable 抱歉,如果我问了一个愚蠢的问题,但是,如果我将 loginUser 方法更改为您建议的方法,它仍然期待 Bool 返回值,那么我应该返回什么?其次,您提供的第二段代码,究竟是什么意思?在 loginUser 方法里面?? 是的,对不起,我忘了删除 -> Bool 部分,现在就这样做。最后一段代码是如何调用 loginUser 方法并使用值【参考方案2】:

Ben,你可以像这样重写你的 loginUser() 方法:

class Login 
    typealias CompletionHandler = (Result<Strin, Error>) -> Void
    func loginUser(email:String, password:String, completion: @escaping CompletionHandler) -> Bool
        let loginRequest = LoginResponse(message: "", oauthToken: "", status: "", userData: [])
        let postRequest = APIRequest(endpoint: "login_buyer", email: email, password: password)
        postRequest.save(loginRequest, completion: result in
            switch result
            case .success(let status):
                completion(.success(status.status))
                print(status.status)
            case .failure(let error):
                completion(.failure(error))
            
        )
    

作为@Scriptable menthind,这是一个异步方法,因此您需要使用完成块而不是return

【讨论】:

UIImage 是从哪里来的?而且你不应该使用 NS 类,几乎总有一个 Swift 版本会更好。在这种情况下出错 我自己的代码复制粘贴错误,我编辑了代码)

以上是关于POST 请求后在 swift 模型中访问值的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 中动态过滤多个值的模型结果

json post后在javascript中从python访问值

API请求后在React渲染方法中访问状态

Firebase创建的模型在swift中具有可选值

Swift:模型结构,使用可选项与空值的初始化

Swift 3:Alamofire POST 请求参数问题