¿Cómo escribir una function genérica apply () en Swift?

¿Hay alguna forma de hacer funcionar lo siguiente en Swift 3?

let button = UIButton().apply { $0.setImage(UIImage(named: "UserLocation"), for: .normal) $0.addTarget(self, action: #selector(focusUserLocation), for: .touchUpInside) $0.translatesAutoresizingMaskIntoConstraints = false $0.backgroundColor = UIColor.black.withAlphaComponent(0.5) $0.layer.cornerRadius = 5 } 

La apply<T> debe tener un cierre del tipo (T)->Void , ejecutarlo en él y, a continuación, simplemente volver self .

Otra opción sería utilizar un operador para esto como " => " (tomó prestada la idea de Kotlin y Xtend idiomas).

NSObject hacer la extensión de NSObject así:

 extension NSObject { func apply<T>(_ block: (T)->Void) -> T { block(self as! T) return self as! T } } 

Pero requiere una statement explícita del tipo de parámetro en el cierre:

 let button = UIButton().apply { (it: UIButton) in it.setImage(UIImage(named: "UserLocation"), for: .normal) it.addTarget(self, action: #selector(focusUserLocation), for: .touchUpInside) ... 

Esto no es conveniente y hace que la idea no valga la pena. El tipo ya está especificado en la creación del object y debería ser posible no repetirlo explícitamente.

¡Gracias!

El protocolo HasApply

Antes que nada definamos el protocolo HasApply

 protocol HasApply { } 

y extensión relacionada

 extension HasApply { func apply(closure:(Self) -> ()) -> Self { closure(self) return self } } 

A continuación, haga que NSObject ajuste a HasApply .

 extension NSObject: HasApply { } 

Eso es

Probémoslo

 let button = UIButton().apply { $0.titleLabel?.text = "Tap me" } print(button.titleLabel?.text) // Optional("Tap me") 

Consideraciones

No utilizaría NSObject (es parte de la forma de hacer Objective-C y supongo que será eliminado en algún momento en el futuro). Prefiero algo como UIView en UIView lugar.

 extension UIView: HasApply { } 

Tuve el mismo problema y terminé resolviéndolo con un operador:

 infix operator <-< : AssignmentPrecedence func <-<<T:AnyObject>(left:T, right:(T)->()) -> T { right(left) return left } let myObject = UIButton() <-< { $0.isHidden = false } 

Hay una biblioteca de Cocoapods muy buena y simple llamada Then que hace exactamente eso. Solo que usa en lugar de apply . Simplemente importe Then y luego puede hacer lo que solicitó el OP:

 import Then myObject.then { $0.objectMethod() } let label = UILabel().then { $0.color = ... } 

A continuación, se describe cómo se implementa el protocolo: https://github.com/devxoul/Then/blob/master/Sources/Then.swift

 extension Then where Self: AnyObject { public func then(_ block: (Self) -> Void) -> Self { block(self) return self } } 

Este es un ejemplo genérico con protocolo y extensión. Deseo que lo ayude

 protocol Container { associatedtype ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get }} class Stack<S>: Container { // original Stack<T> implementation var items = [S]() func push(item: S) { items.append(item)} func pop() -> S { return items.removeLast() } // conformance to the Container protocol func append(item: S) { self.push(item: item) } var count: Int { return items.count } subscript(i: Int) -> S { return items[i] }} extension Stack { var topItem: S? { return items.isEmpty ? nil : items[items.count - 1] }} var stringStack = Stack<String>() var intStack = Stack<Int>()