如何在更改屏幕之前从扩展调用协议

  • 本文关键字:扩展 调用 协议 屏幕 swift
  • 更新时间 :
  • 英文 :


在点击进入另一个屏幕的按钮之前,我需要从扩展中获取一个值,我该怎么做?

这是viewController中的IBAction。当我点击它向API发出请求,然后在第二个屏幕上向全局变量发送一个值:

@IBAction func enter(_ sender: UIButton) {

if let login = loginTextfield.text, let password = passwordTextfield.text {
loginManager.performLoginRequest(login, password)
resultsViewController.receivedToken = token
navigationController?.pushViewController(resultsViewController, animated: true)
}
}
extension LoginViewController: LoginManagerDelegate {

func didUpdateLogin(with login: LoginModel) -> (Bool, String) {
success = login.success
token = login.token

return (success, token)
}
}

经理:

import Foundation
protocol LoginManagerDelegate {
func didUpdateLogin(with login: LoginModel) -> (Bool, String)
}
struct LoginManager {

var delegate: LoginManagerDelegate?

func performLoginRequest(_ login: String, _ password: String) {
let url = URL(string: "https://private-anon-1a0df64d9c-ibmfc.apiary-mock.com/login")!

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = """
{n  "username": "(login)",n  "password": "(password)"n}
""".data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let response = response {
print(response)
if let data = data, let body = String(data: data, encoding: .utf8) {
print(body)
if let login = self.parseJSON(loginData: data) {
self.delegate?.didUpdateLogin(with: login)
}
}
} else {
print(error ?? "Unknown error")
}
}
task.resume()
}

func parseJSON(loginData: Data) -> LoginModel? {

let decoder = JSONDecoder()

do {
let decodedData = try decoder.decode(LoginData.self, from: loginData)

let success = decodedData.success
let token = decodedData.data.token

let login = LoginModel(success: success, token: token)

return login
} catch {
print(error.localizedDescription)
return nil
}
}
}

我的问题是,这个扩展只是在我点击按钮后被调用。通过这种方式,resultsViewController.receivedToken不会从token获得值。那么,在单击IBAction之前,我如何调用didUpdateLogin(将其值传递给successtoken(?

这种行为的原因是您使用的后台线程:

(1( 您调用loginManager.performLoginRequest(login, password),然后它启动一个后台线程来实际处理该请求
(2(在此期间,您的代码将继续运行,执行resultsViewController.receivedToken = token
(3(由于(1(尚未完成,您的token仍然是nil(或旧的token(。

多种可能的解决方案之一:在performLoginRequest的参数中添加一个块,在其中调用

resultsViewController.receivedToken = token
navigationController?.pushViewController(resultsViewController, animated: true)

通过这种方式,你可以确保只有在(!(登录成功后才调用代码,因为你在等待它。同时,你可以显示一个加载微调器或类似的东西。登录是一项用户只需等待的任务,通常(取决于应用程序(没有办法。

代码最终可能看起来像这样:

loginManager.performLoginRequest(login, password) {
resultsViewController.receivedToken = token
navigationController?.pushViewController(resultsViewController, animated: true)
}

而你的LoginManager会有一个类似的方法

func performLoginRequest(_ login: String,
_ password: String,
completion: @escaping () -> Void)

稍后在您的Dispatch:中使用

DispatchQueue.main.async {
let loginVC = LoginViewController()
loginVC.didUpdateLogin(login: login)
completion()
}

最新更新