如何在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>()