如何在Swift中编写一个通用的apply()函数?

有没有什么办法可以在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 } 

apply<T>函数应该使用类型(T)->Void的闭包,运行它将self传递给它,然后简单地返回self

另一个选择是使用一个运算符,例如“ => ”(借用Kotlin和Xtend语言的思路)。

试图做这样的NSObject扩展:

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

但是它需要在闭包中明确声明参数类型:

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

这不方便,使整个想法不值得努力。 该类型已经在创建对象时指定,并且应该可以不明确地重复。

谢谢!

HasApply协议

首先让我们定义一下HasApply协议

 protocol HasApply { } 

和相关的扩展

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

接下来让让NSObject符合HasApply

 extension NSObject: HasApply { } 

而已

我们来测试一下

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

注意事项

我不会使用NSObject (这是Objective-C做事的一部分,我认为它将在未来某个时候被删除)。 我宁愿像UIView相反。

 extension UIView: HasApply { } 

我遇到了同样的问题,并最终与运营商解决了问题:

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

有一个非常好的,简单的Cocoapods库叫做Then就是这么做的。 只有它使用,而不是apply 。 只需导入Then ,你可以做OP所要求的:

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

以下是协议的实现方式: 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 } } 

这是通用协议和扩展的例子。 我希望你帮助你

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