Как экранировать значение с помощью throw '() throws -> Bool' не конвертируется в 'Bool'

Я новичок в скором времени, и я был, вероятно, более часа вокруг этого.

Я делаю запрос к веб-службе, и теперь я хочу действовать в соответствии с кодом ответа (200 Ok) или другим, но я не могу понять синтаксис для возврата значения и выдачи исключения.

typealias  ThrowableCallBack = () throws -> Bool


func authenticate()
{
    let services = ServiceManager()


    do {
         try services.login(username: emailField.text!, password: passwordField.text!, authenticated: { auth in
            self.loadingDialog.dismiss(animated: false, completion: {
                if (auth) // '() throws -> Bool' is not convertible to 'Bool'
                {
                    self.performSegue(withIdentifier: "LoginSegue", sender: self)
                }
            })
        } )
    }
    catch RequestError.invalidRequest {
        showLoginFailedAlert()
    }
    catch {
        showLoginFailedAlert()
    }
}

Потом на услуги

func login(username : String, password : String, authenticated: @escaping (_ inner: ThrowableCallBack) -> Void )
{
    let parameters = [
        "_username" : username,
        "_password" : password
    ]

    let request = makePostCall(request: "login", parameters: parameters, completion: {
        response in

        let statusCode = String(describing: response["statusCode"]!)
        if (statusCode != "200")
        {
            authenticated( { throw RequestError.invalidRequest })
        }
        else
        {
            self.jwt = String(describing: response["jwt"]!)
            authenticated( { return true })
        }
    } )

}

Как я должен исправить auth '() throws -> Bool' не конвертируемый в 'Bool', чтобы можно было как перехватить ошибку, так и успешно? Мой псевдоним правильный?

заранее спасибо

2 ответа

Решение

В вашем login метод, тип параметра authenticated является @escaping (_ inner: ThrowableCallBack) -> Void,

Итак, закрытие перешло к authenticated принимает один параметр типа ThrowableCallBack, что означает параметр auth в вашем закрытии имеет тип ThrowableCallBackне Bool,

Вам нужно использовать auth как if try auth() как ThrowableCallBack принимает один параметр типа () а также throws,

func authenticate() {
    let services = ServiceManager()

    services.login(username: emailField.text!, password: passwordField.text!, authenticated: { auth in
        self.loadingDialog.dismiss(animated: false, completion: {
            do {
                if try auth() {
                    self.performSegue(withIdentifier: "LoginSegue", sender: self)
                }
            } catch RequestError.invalidRequest {
                self.showLoginFailedAlert()
            } catch {
                self.showLoginFailedAlert()
            }
        })
    } )
}

Чтобы это работало, вам может потребоваться изменить тип authenticated следующее:

func login(username : String, password : String,
           authenticated: @escaping (_ inner: @escaping ThrowableCallBack) -> Void ) {
    //...
}

В любом случае, тип замыкания, принимающий параметр другого типа замыкания, очень запутан, и вам лучше пересмотреть свой дизайн.

(Сложение)

Когда вы получаете ошибки во время выполнения, говорящие о некоторых вещах основного потока, вам может потребоваться использовать DispatchQueue.main как найдено во многих асинхронных примерах:

func authenticate() {
    let services = ServiceManager()

    services.login(username: emailField.text!, password: passwordField.text!, authenticated: { auth in
        DispatchQueue.main.async {
            self.loadingDialog.dismiss(animated: false, completion: {
                do {
                    if try auth() {
                        self.performSegue(withIdentifier: "LoginSegue", sender: self)
                    }
                } catch RequestError.invalidRequest {
                    self.showLoginFailedAlert()
                } catch {
                    self.showLoginFailedAlert()
                }
            })
        }
    } )
}

Вы можете взглянуть на эту тему

Мы используем Completion перечислить, чтобы сделать это

public enum Completion<E:Error> {
    case success
    case failure(E)
}

Реализуйте это в вашей функции следующим образом:

func login(username : String, password : String, authenticated: @escaping (Completion<ServiceError> )
{
    ...
    if (statusCode != "200") {
        authenticated(.failure(ServiceError.accessDenied))
    } else {
        self.jwt = String(describing: response["jwt"]!)
        authenticated(.success)
    }
    ...
}

Проверьте это следующим образом:

try services.login(username: emailField.text!, password: passwordField.text!, authenticated: { auth in
    switch auth {
    case .success:  //handle success
    case .failure(let error): print(error)
    }
}

Заметка ServiceError это перечисление, которое реализует Error и содержит все различные виды сервисных ошибок, которые мы потенциально можем получить.

Мы используем аналогичное перечисление в случае, когда мы хотим вернуть результат.

public enum Result<Value, E:Error> {
    case success(Value)
    case failure(E)
}
Другие вопросы по тегам