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

时间:2019-07-19 10:55:12

标签: json swift post swiftui

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

模型类

// 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值?

2 个答案:

答案 0 :(得分: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
}

答案 1 :(得分:0)

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 menthiond,这是一个异步方法,因此,您需要使用完成块,而不是 return