Swift 带有成功和失败处理程序的完成块
Swift completion block with success and failure handler
我正在研究 Swift 应用程序的登录过程,我想知道我是否应该在该函数中包含成功和失败处理程序,该函数检查用户是否已成功登录.
我想在这里做的是仅当用户成功登录时触发 successCompletion() 块,否则显示带有消息的警报。
我觉得登录函数需要多个参数,而且我认为很难弄清楚它处理来自 LoginViewController 的两个完成处理程序。那么,我应该在函数中同时包含错误和成功处理程序,还是更好地以某种方式将它们分开?
在我的 LoginViewController 中,
class LoginViewController: UIViewController {
private let loginView = LoginView()
@objc func loginButtonAction() {
let idInputValue = loginView.loginIdTextField.text!
let passInputValue = loginView.passwordTextField.text!
LoginAPI().login(with: idInputValue, and: passInputValue, errorCompletion: show(message:)) { _ in
let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as! SceneDelegate
sceneDelegate.setRootVC(to: HomeViewController())
}
func showAlert(message: String) {
let okAction = UIAlertAction(title: Alert.ButtonTitle.ok, style: .default, handler: nil)
showAlert(title: Alert.Title.loginError, message: message, actions: [okAction], style: .alert)
}
}
和我的 LoginAPI class,
import Alamofire
class LoginAPI {
static var accountInfo: AccountInfo?
private let loginEndpoint = "https://example.com"
func login(with id: String, and password: String, errorCompletion: @escaping (_ m: String) -> Void?, successCompletion: @escaping () -> Void) {
let parameter: [String: Any] = ["id": id, "password": password]
AF.request(loginEndpoint, method: .post, parameters: parameter)
.validate()
.responseJSON { response in
guard let data = response.data else {
errorCompletion(response.error)
return
}
let decoder: JSONDecoder = JSONDecoder()
var accountInfo: AccountInfo?
do {
accountInfo = try decoder.decode(AccountInfo.self, from: data)
} catch {
errorCompletion(error)
}
LoginAPI.accountInfo = accountInfo
DispatchQueue.main.async {
successCompletion()
}
}
}
}
更新了函数
func login(with id: String, and password: String, completed: @escaping (Result<AccountInfo, LoginError>) -> Void) {
let parameter: [String: Any] = ["id": id, "password": password]
AF.request(loginEndpoint, method: .post, parameters: parameter)
.responseDecodable(of: AccountInfo.self) { response in
switch(response.result) {
case .success(let data):
completed(.success(data))
case .failure(let error):
completed(.failure(.test))
}
}
}
use Result
很常见。通过返回结果,您可以严格履行 login()
的责任并在其他地方处理结果。而且确实也避免了两个完成块的不明确。
其他说明:您不需要DispatchQueue.main.async
因为AF.request
完成块已经在主线程上了。
我正在研究 Swift 应用程序的登录过程,我想知道我是否应该在该函数中包含成功和失败处理程序,该函数检查用户是否已成功登录.
我想在这里做的是仅当用户成功登录时触发 successCompletion() 块,否则显示带有消息的警报。 我觉得登录函数需要多个参数,而且我认为很难弄清楚它处理来自 LoginViewController 的两个完成处理程序。那么,我应该在函数中同时包含错误和成功处理程序,还是更好地以某种方式将它们分开?
在我的 LoginViewController 中,
class LoginViewController: UIViewController {
private let loginView = LoginView()
@objc func loginButtonAction() {
let idInputValue = loginView.loginIdTextField.text!
let passInputValue = loginView.passwordTextField.text!
LoginAPI().login(with: idInputValue, and: passInputValue, errorCompletion: show(message:)) { _ in
let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as! SceneDelegate
sceneDelegate.setRootVC(to: HomeViewController())
}
func showAlert(message: String) {
let okAction = UIAlertAction(title: Alert.ButtonTitle.ok, style: .default, handler: nil)
showAlert(title: Alert.Title.loginError, message: message, actions: [okAction], style: .alert)
}
}
和我的 LoginAPI class,
import Alamofire
class LoginAPI {
static var accountInfo: AccountInfo?
private let loginEndpoint = "https://example.com"
func login(with id: String, and password: String, errorCompletion: @escaping (_ m: String) -> Void?, successCompletion: @escaping () -> Void) {
let parameter: [String: Any] = ["id": id, "password": password]
AF.request(loginEndpoint, method: .post, parameters: parameter)
.validate()
.responseJSON { response in
guard let data = response.data else {
errorCompletion(response.error)
return
}
let decoder: JSONDecoder = JSONDecoder()
var accountInfo: AccountInfo?
do {
accountInfo = try decoder.decode(AccountInfo.self, from: data)
} catch {
errorCompletion(error)
}
LoginAPI.accountInfo = accountInfo
DispatchQueue.main.async {
successCompletion()
}
}
}
}
更新了函数
func login(with id: String, and password: String, completed: @escaping (Result<AccountInfo, LoginError>) -> Void) {
let parameter: [String: Any] = ["id": id, "password": password]
AF.request(loginEndpoint, method: .post, parameters: parameter)
.responseDecodable(of: AccountInfo.self) { response in
switch(response.result) {
case .success(let data):
completed(.success(data))
case .failure(let error):
completed(.failure(.test))
}
}
}
use Result
很常见。通过返回结果,您可以严格履行 login()
的责任并在其他地方处理结果。而且确实也避免了两个完成块的不明确。
其他说明:您不需要DispatchQueue.main.async
因为AF.request
完成块已经在主线程上了。