Is there any way to get the following working in Swift 3?
let button = UIButton().apply {
$0.setImage(UIImage(named: \"UserLocation\"), for: .normal
First of all lets define the HasApply protocol
protocol HasApply { }
and related extension
extension HasApply {
func apply(closure:(Self) -> ()) -> Self {
closure(self)
return self
}
}
Next let make NSObject conform to HasApply.
extension NSObject: HasApply { }
Let's test it
let button = UIButton().apply {
$0.titleLabel?.text = "Tap me"
}
print(button.titleLabel?.text) // Optional("Tap me")
I wouldn't use
NSObject(it's part of the Objective-C way of doing things and I assume it will be removed at some point in the future). I would prefer something likeUIViewinstead.
extension UIView: HasApply { }
Alain has a good answer if you're not allergic to custom operators. If you'd rather not use those, the best alternative I could come up with was:
@discardableResult func apply<T>(_ it:T, f:(T)->()) -> T {
f(it)
return it
}
which then allows you to use:
let button = apply(UIButton()) { $0.setTitleText("Button") }
It's not quite the same, but works out pretty well in general and has the advantage that T is completely unrestrained. It's an obviously contrived example, but:
func apply<T,R>(_ it:T, f:(T)->R) -> R {
return f(it)
}
even allows:
print("\(apply(32) { $0 + 4 })")
There's a very good and simple Cocoapods library available called Then that does exactly that. Only that it uses then instead of apply. Simply import Then and then you can do as the OP asked for:
import Then
myObject.then {
$0.objectMethod()
}
let label = UILabel().then {
$0.color = ...
}
Here's how the protocol is implemented: https://github.com/devxoul/Then/blob/master/Sources/Then/Then.swift
extension Then where Self: Any {
public func then(_ block: (Self) throws -> Void) rethrows -> Self {
try block(self)
return self
}
I had the same issue and ended up solving it with an operator:
infix operator <-< : AssignmentPrecedence
func <-<<T:AnyObject>(left:T, right:(T)->()) -> T
{
right(left)
return left
}
let myObject = UIButton() <-< { $0.isHidden = false }