Вложенные замыкания не любят список аргументов

UIView необходимо изменить метку предупреждения в зависимости от обработчика завершения пользовательского элемента управления:

    voucherInputView.completionHandler = {[weak self] (success: Bool) -> Void in

        self?.proceedButton.enabled = success
        self?.warningLabel.alpha = 1.0

        if success
        {
            self?.warningLabel.text = "Code you entered is correct"
            self?.warningLabel.backgroundColor = UIColor.greenColor()
        }
        else
        {
            self?.warningLabel.text = "Code you entered is incorrect"
            self?.warningLabel.backgroundColor = UIColor.orangeColor()
        }


        UIView.animateWithDuration(NSTimeInterval(1.0), animations:{ ()-> Void in
            self?.warningLabel.alpha = 1.0
        })

Последний блок анимации показывает ошибку в форме.

Cannot invoke 'animateWithDuration' with an argument list of type '(NSTimeInterval), animations: ()-> Void)'

Если я назову это где-то за пределами закрытия завершения, это сработает.


person Ilker Baltaci    schedule 24.09.2014    source источник


Ответы (2)


Проблема в том, что замыкание неявно возвращает результат этого выражения:

self?.warningLabel.alpha = 1.0

но само закрытие объявлено как возвращающее Void.

Добавление явного return должно решить проблему:

UIView.animateWithDuration(NSTimeInterval(1.0), animations: { ()-> Void in
    self?.warningLabel.alpha = 1.0
    return
})
person Antonio    schedule 24.09.2014
comment
Это исправило это для меня, но не мог бы кто-нибудь объяснить, почему это поведение такое странное и неожиданное для многих людей? Кстати, в вашем примере вы можете заменить ()->Void на _ и добавить return с помощью ; return в ту же строку. ТАКЖЕ, вы можете написать ; () вместо однострочного return. :) - person BastiBen; 17.12.2014
comment
@badcat Когда вы пишете закрытие без ключевого слова return, закрытие автоматически возвращает последний оператор. Он делает это так, что array.sort {$0.index < $1.index} работает. Если ваш последний оператор является присваиванием необязательного типа, он вернет Void?. Вы можете увидеть это, если позволите Xcode вывести тип: () -> ()?. Пустой оператор return неявно возвращает Void (необязательный тип). Забавный факт: Void — это typealias вместо (), пустой кортеж, который возвращают все функции, если вы не вводите оператор return. (1/2) - person vrwim; 23.04.2015
comment
(2/2) Функции могут обрабатывать необязательные Void как результаты последней строки, поскольку им не нужно угадывать никаких returns. Все возвраты должны быть явными. - person vrwim; 23.04.2015
comment
@badcat В чем прелесть написания ; return или ; () вместо return? Прежде всего, ; return нужно набрать больше символов, чем return? Или, если Антонио может ответить, пожалуйста. Заранее спасибо. - person Unheilig; 05.06.2015
comment
@Unheilig: вы можете написать закрытие в одну строку - в этом случае 2 оператора должны быть разделены: self?.warningLabel.alpha = 1.0; return - person Antonio; 05.06.2015
comment
@ Антонио Теперь я вижу это. Уже проголосовал перед вашим ответом. Спасибо. - person Unheilig; 05.06.2015

Решение Антонио также применимо к вложенным замыканиям, таким как выполнение запроса AFNetworking в обработчике UITableViewRowAction.

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {

    let cleanRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Do Stuff", handler: {[weak self](action: UITableViewRowAction!, indexPath: NSIndexPath!) in

        AFHTTPSessionManager(baseURL: NSURL(string: "http://baseurl")).PUT("/api/", parameters: nil, success: { (task: NSURLSessionDataTask!, response: AnyObject!) -> Void in

                // Handle success

                self?.endEditing()
                return
            }, failure: { (task: NSURLSessionDataTask!, error: NSError!) -> Void in

                // Handle error

                self?.endEditing()
                return
        })
        return

    })

    cleanRowAction.backgroundColor = UIColor.greenColor()
    return [cleanRowAction]
}
person Longmountain    schedule 24.09.2014