ios - 在 swift 4 中返回之前强制等待 Alamofire 响应

标签 ios swift concurrency grand-central-dispatch

我遇到过这样的情况:我必须在注册和通过 OTP 代码登录时检查所提供的手机号码。我在我的 Accounts 类中进行了所有设置,以便在 SignUpViewControllerSignInViewController 上重用它们。

ViewControllers中,我想先发送OTP,然后检查它是否是从服务器响应发送来推送VerificationViewController,我正在使用Alamofire 用于网络,SwiftyJSON 用于解析 JSON 响应。现在让我们深入挖掘问题的核心:

这是我的 SignUpViewController 类的一部分

var acc: Accounts = Accounts()

@IBAction func signupAction(_ sender: Any) {
        if validateFields() {
            let fname = self.firstName.text!
            let lname = self.lastName.text!
            let pnum = self.phoneNumber.text!
            self.acc.setFirstName(fn: fname)
            self.acc.setLastName(ln: lname)
            self.acc.setPhoneNumber(pn: pnum)
            let result = self.acc.sendOTP()
            if (result) {
                let targetVC = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "signupVerfication") as? SignupVerficationViewController
                self.navigationController?.pushViewController(targetVC!, animated: true)
            }
            else {
                CustomComponents().alertWithTitle(title: "Error", message: "Unable to Verify Phone Number,Please Try again!", ViewController: self)
            }
        }
}

这是我的 Accounts 类的一部分

func sendOTP() -> Bool {
        let conf = APIConfig()
        var returnedResult = false
        conf.setURL(url: "patient/auth/send-totp")
        conf.setHeader(head: ["Content-Type": "Application/json"])
        conf.setBody(body: ["phone_number": self.phoneNumber])
        print(self.phoneNumber)
        Alamofire.request(conf.getURL(), method: .post, parameters: conf.getBody(), encoding: JSONEncoding.default, headers: conf.getHeader()).validate(statusCode: 200..<600).responseData { response in
            let status = response.response?.statusCode
            print(status!)
            let swiftJSONVar = JSON(response.result.value!)
            print(swiftJSONVar)
            if (status == 200) {
                returnedResult = true
            }
        }
        return returnedResult
    }

每当我运行应用程序时,我总是会收到警报作为输出,尽管事实上,如您所见,我通过在此处打印它 print(status!) 和此处 来调试响应打印(swiftJSONVar)。打印的输出是 200 作为状态代码,我得到了其余的响应。

我一直在网上查找许多教程,例如:Grand Central Dispatch Tutorial for Swift 4Secure Coding With Concurrency in Swift 4等等,但无法在我的代码块上实现 GCD。

我需要你的帮助吗?

最佳答案

sendOTP 方法的返回类型为 Bool,它会立即返回,因为 Alamofire 请求是异步,并且您在顶部将 returnedResult 的值设置为 false,其中立即返回,无需等待响应。从 Alamofire 发出响应后,returnedResult 将设置为 true,但无法通知调用者。由于 sendOTP 方法返回 false,因此显示错误警报。

使用闭包而不是从 sendOTP 返回 bool,后者接受 Bool 并返回 void

func sendOTP(_ completion: @escaping (Bool) -> Void) {
    let conf = APIConfig()
    var returnedResult = false
    conf.setURL(url: "patient/auth/send-totp")
    conf.setHeader(head: ["Content-Type": "Application/json"])
    conf.setBody(body: ["phone_number": self.phoneNumber])
    print(self.phoneNumber)
    Alamofire.request(conf.getURL(), method: .post, parameters: conf.getBody(), encoding: JSONEncoding.default, headers: conf.getHeader()).validate(statusCode: 200..<600).responseData { response in
        let status = response.response?.statusCode
        print(status!)
        let swiftJSONVar = JSON(response.result.value!)
        print(swiftJSONVar)
        if (status == 200) {
            completion(true)
        } else {
            completion(false)
        }
    }
}

现在你可以打电话了

self.acc.sendOTP { (result) in
    if result {
        //show vc
        let targetVC = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "signupVerfication") as? SignupVerficationViewController
        self.navigationController?.pushViewController(targetVC!, animated: true)
    } else {
        //show error alert
        CustomComponents().alertWithTitle(title: "Error", message: "Unable to Verify Phone Number,Please Try again!", ViewController: self)
    }
}

连同 GCD教程,我推荐URLSessionAlamofire教程以及了解网络在 iOS 中如何工作。

关于ios - 在 swift 4 中返回之前强制等待 Alamofire 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53516425/

相关文章:

java - 使用线程池将紧耦合方法转换为松耦合的优雅方法

java - 在 for each 循环中同步仍然会抛出 ConcurrentModificationExceptions

android - 如何让我的智能家居应用在 Google Home 应用中显示为建议

ios - 协调 CACurrentMediaTime() 和 deviceCurrentTime

ios - 为什么 iPhone XR、XS 和 XS Max 不将环境图像应用于 ARKit 中的场景?

iphone - self.interfaceOrientation 导致在 iOS 4.x 上调用 shouldAutorotateToInterfaceOrientation

ios - 更改 UIImageView 的位置后是否需要更新约束

ios - prepareForSegue 在 vi​​ewDidLoad 加载所有 IBOutlets 之前触发 didSet

c# - 与 Entity Framework 和 SQL (ADO.NET) 的并发性

swift - 如何在 iOS Swift 中更新字典的值?