How to write a common apply () function in Swift?

Is there a way to get the next job in 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 } 

The apply<T> function should take a closure of type (T)->Void , running the self run in it, and then just return self .

Another option would be to use the operator for this type of " => " (borrowed the idea from Kotlin and Xtend languages.)

Tried to do the NSObject extension as follows:

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

But this requires an explicit declaration of the parameter type in the closure:

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

This is not convenient, and the whole idea is not worth the effort. The type is already specified when creating the object, and it should be possible not to repeat it explicitly.

Thanks!

+8
source share
5 answers

HasApply Protocol

First of all, define the HasApply protocol

 protocol HasApply { } 

and related extension

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

Next, make NSObject match HasApply .

 extension NSObject: HasApply { } 

What he

Let me check it out

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

Questions

I would not use NSObject (this is part of Objective-C's way of doing things, and I assume that it will be deleted at some point in the future). Instead, I would prefer something like a UIView .

 extension UIView: HasApply { } 
+15
source

I had the same problem, and I decided to solve it using the operator:

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

There is a very nice and simple Cocoapods library called “ Then which does exactly that. Only that it uses then instead of apply . Just import Then and then you can do as the OP requested:

 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

 public func then(_ block: (Self) throws -> Void) rethrows -> Self { try block(self) return self } 
+4
source

Alain has a good answer if you are not allergic to custom operators. If you do not want to use them, the best alternative I can offer 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") } 

This is not exactly the same, but overall works pretty well and has the advantage that T is completely unrestrained. This is a clearly contrived example, but:

 func apply<T,R>(_ it:T, f:(T)->R) -> R { return f(it) } 

even allows you to:

 print("\(apply(32) { $0 + 4 })") 
0
source

This is an example of Generic With Protocol and Extension. I wish you to help you.

 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>() 
-1
source

All Articles