Элегантный способ пропускать пустые закрытия в Swift

В Swift мне часто приходится пропускать замыкание на ноль для метода, чтобы соответствовать методу ожидаемых параметров (arity). В старые добрые времена Obj C можно было пройти nil для обратного вызова noop и сделать с ним. Есть ли более быстрый и элегантный способ сделать это в Swift без прохождения пустого блока, как показано ниже?

UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (UIAlertAction) -> Void in }) // do nothing in callback

Полный пример:

import UIKit

class UIAlertControllerFactory {
    class func ok(title: String, message: String) -> UIAlertController {
        var alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        var okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (UIAlertAction) -> Void in
        })
        alertController.addAction(okAction)
        return alertController
    }
}

Ответы

Ответ 1

Общий способ, если вы не можете пройти nil:

var okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default,
    handler:{ _ in })

Вы также можете передать nil в этом случае, потому что (с iOS 9.0) обработчик является Optional:

var okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default,
    handler:nil)

Ответ 2

Согласно документации Xcode, UIAlertAction имеет метод convenience init со следующим объявлением:

convenience init(title: String, style: UIAlertActionStyle, handler: ((UIAlertAction!) -> Void)!) 

Как вы можете видеть, параметр handler является Неявно Unwrapped Необязательный типа ((UIAlertAction!) -> Void)!. Поэтому вы можете передать nil для этого. Например, вы можете создать экземпляр UIAlertController, содержащий один UIAlertAction с handler: nil:

let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
presentViewController(alertController, animated: true, completion: nil)

Поэтому вам не нужно создавать пустой блок для handler.

Ответ 3

Вы можете определить noop, который будет использоваться как закрытие по умолчанию, которое ничего не делает: (Ссылка: https://realm.io/news/closures-api-design)

func noop() {}

func noop<T>(value: T) {}

func noop<T>() -> T? { return nil }

func noop<T, S>(value: T) -> S? { return nil }

Для использования:

var okAction = UIAlertAction(title: "Ok", 
                             style: UIAlertActionStyle.Default, 
                           handler: noop)

Ответ 4

extension UIAlertAction {
    convenience init(title: String, style: UIAlertActionStyle) {
        return self.init(title: title, style: style, handler:  { (UIAlertAction) -> Void in })
    }
}

и просто оставьте последний аргумент. Вы можете поместить это в свой "factory".