AppDelegate:

func userAuthorized() -> Bool { let username : String = UserDefaults.standard.string(forKey: "username") ?? "" let password : String = UserDefaults.standard.string(forKey: "password") ?? "" var tempToken:String = "" if(!username.isEmpty && !password.isEmpty)//потом это { let json: [String: String] = ["username": username, "password": password] login(json: json) { [weak self] token, code in guard let self = self else { return } guard let token = token, !token.isEmpty else { print("error") return } print("ok") print(token) tempToken = token print("temp " + tempToken) UserDefaults.standard.setValue(username, forKey: "userEmail"); UserDefaults.standard.setValue(password, forKey: "userPassword"); UserDefaults.standard.setValue(token, forKey: "token"); UserDefaults.standard.synchronize(); } } else { return false } if(!tempToken.isEmpty){// сначало это вызывается return true } return false } 

REST module:

 func login(json: Any, callback: @escaping (_ token: String?, _ code: Int?) -> ()) { guard let url = URL(string: ngrok+"/api/auth/token/create")else{return} var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField:"Content-Type") guard let httpBody = try? JSONSerialization.data(withJSONObject: json, options: [])else {return} request.httpBody = httpBody URLSession(configuration: .default).dataTask(with: request){(data, response, error) in if let response = response{ print(response) } if let error = error{ print(error) } if let httpResponse = response as? HTTPURLResponse{ guard let data = data else{return} do{ print(data) if let json_response = try JSONSerialization.jsonObject(with: data, options: [])as? [String:Any]{ if let temp_token = json_response["auth_token"]{ print(temp_token as! String) DispatchQueue.main.async { callback(temp_token as? String, httpResponse.statusCode) } } } } catch{ print(error) } } }.resume() } 

Two problems:

1) I look at the server logs and see the code 200, and !tempToken.isEmpty issues an empty token. Put a stop point and really, first checked !tempToken.isEmpty , and then comes the login function call. Why is that? Is this because the login function is asynchronous? Then how can you wait for its execution (successful or not), and then check tempToken? Or is it a bad decision?

2) I just can not catch the error when the server is turned off. Put a stop point and that's what I get: comes to URLSession(configuration: .default).dataTask(with: request){(data, response, error) , and then immediately to resume() and print(error) does not output anything. Surely this is again due to asynchrony.

I see only one option - to make the login function synchronous, if possible. But I'm not sure how good this decision is, if by default it goes asynchronous.

By the way, if you call the function from the loginView, then everything works fine, I don’t think that it’s impossible to catch the error with the server turned off:

 @IBAction func loginButtonTapped(_ sender: Any) { let userEmail = emailOrUsernameField.text; let userPassword = passwordField.text; if(userEmail!.isEmpty || userPassword!.isEmpty){ self.errorLabel.text = "Не все поля заполенны" if(userEmail!.isEmpty && !userPassword!.isEmpty){ textFieldsColor(textField: emailOrUsernameField, color: redBorder ) } else if (!userEmail!.isEmpty && userPassword!.isEmpty){ textFieldsColor(textField: passwordField, color: redBorder) } else{ textFieldsColor(textField: emailOrUsernameField, color: redBorder) textFieldsColor(textField: passwordField, color: redBorder) } }else { let json: [String: String] = ["username": userEmail!, "password": userPassword!] login(json: json) { [weak self] token, code in guard let self = self else { return } guard let token = token, !token.isEmpty else { print("error") self.errorLabel.text = "Невенрный логин или пароль." return } print(code) self.errorLabel.text = "" UserDefaults.standard.setValue(userEmail, forKey: "username"); UserDefaults.standard.setValue(userPassword, forKey: "password"); UserDefaults.standard.setValue(token, forKey: "token"); UserDefaults.standard.synchronize(); let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main) self.window = UIWindow(frame: UIScreen.main.bounds) self.window!.makeKeyAndVisible() self.window!.rootViewController = storyboard.instantiateInitialViewController() } } } 

    1 answer 1

    Just replace return with completion and get rid of additional problems.

     func userAuthorized() -> Bool { на func userAuthorizedCheck(after completion: @escaping (Bool) -> Void) { 

    And use as you need:

     if <#Условие#> { ... completion(true) } else { someAsyncOperation() { if <#Нужные проверки#> { ... completion(true) } else { completion(false) } } } 

    Use:

     userAuthorizedCheck(after: { [<#weak capture list#>] result in // Что нудно сделать после проверки }) 
    • Here it is . If with completion (false) at the very end of userAuthorizedCheck, after all the checks, then I get false anyway. And if I remove completion (false), I get Thread 1: signal SIGABRT. - hohfiofi
    • I also decided to try this, and still, first check and then request. - hohfiofi
    • The completionHandler is the same. - hohfiofi
    • Combined the post and login function into one, and it all worked. Thank. Only now such code needs to be used. - hohfiofi
    • @hohfiofi, various particular implementations are possible. You can combine logically, you can conversely detail on the set of very small steps and respond to each of them in some way. Depends on the task and organization. - VAndrJ