在点击进入另一个屏幕的按钮之前,我需要从扩展中获取一个值,我该怎么做?
这是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
(将其值传递给success
和token
(?
这种行为的原因是您使用的后台线程:
(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()
}