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完成块已经在主线程上了。