我想通过扩展程序编写一个函数,让我们说UIView
。该函数应该具有与获取调用函数的对象相同类型的参数,例如可以在块实现中使用的UIButton
或UIImageView
,当然还有实际类型。
与往常一样,代码可以解释得最好:
extension UIView {
func performOnMe<T>(_ block: (_ obj: T) -> Void) -> T {
block(self)
return self
}
}
let button = UIButton(frame: CGRect.zero)
button.performOnMe { $0.alpha = 1 }
.performOnMe { $0.setTitle("Title", for: .normal) }
.performOnMe { $0.backgroundColor = UIColor.red }
let image = UIImageView(frame: CGRect.zero)
image.performOnMe { $0.alpha = 1 }
.performOnMe { $0.image = nil }
当然,该片段无法编译,因为Swift无法推断T的类型。这就是挑战。我该如何解决?它有可能吗?
答案 0 :(得分:2)
&#34;技巧&#34;是使用默认实现定义协议
在扩展名中,并使UIView
符合该协议:
protocol PerformOnMe { }
extension PerformOnMe {
@discardableResult func performOnMe(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
extension UIView: PerformOnMe {}
添加@discardableResult
属性以避免使用
&#34;表达结果未使用&#34;呼叫链中的警告:
let button = UIButton(frame: CGRect.zero)
button.performOnMe { $0.alpha = 1 }
.performOnMe { $0.setTitle("Title", for: .normal) }
.performOnMe { $0.backgroundColor = UIColor.red }
let imageView = UIImageView()
image.performOnMe { $0.alpha = 1 }
.performOnMe { $0.image = nil }
答案 1 :(得分:1)
如果我理解正确,你想扩展UIView的特定子类?
在这种情况下,我建议你定义一个协议并用它扩展你想要的类,如下所示:
protocol Perform {}
// This extension is only available to UIViews (you can replace with Any or AnyObject to have it available on everything or all objects)
extension Perform where Self: UIView {
func performOnMe(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
// Apply protocol to all UIViews
extension UIView: Perform {}
// Usage
UIView().performOnMe { (view) in
// Do something
}
答案 2 :(得分:1)
一种稍微不同的方法,适用于任何对象,而不仅仅是UIViews
infix operator <~: AdditionPrecedence
@discardableResult public func <~ <T>(obj: T, block: (T) -> ()) -> T {
block(obj)
return obj
}
let button = UIButton(frame: CGRect.zero)
<~ { $0.alpha = 1 }
<~ { $0.setTitle("Title", for: .normal) }
<~ { $0.backgroundColor = UIColor.red }
答案 3 :(得分:1)
您可以使用运算符为所有类实现此目的:
infix operator <-< : AdditionPrecedence
func <-<<T>(left:T, right:(T)->()) -> T
{
right(left)
return left
}
let button = UIButton(frame: CGRect.zero)
<-< { $0.alpha = 0.3 }
<-< { $0.setTitle("Title", for: .normal) }
<-< { $0.backgroundColor = UIColor.blue }
or
let button = UIButton(frame: CGRect.zero) <-< {
$0.alpha = 0.3
$0.setTitle("Title", for: .normal)
$0.backgroundColor = UIColor.blue
}