在扩展程序

时间:2017-07-14 15:11:33

标签: ios swift generics

我想通过扩展程序编写一个函数,让我们说UIView。该函数应该具有与获取调用函数的对象相同类型的参数,例如可以在块实现中使用的UIButtonUIImageView,当然还有实际类型。

与往常一样,代码可以解释得最好:

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的类型。这就是挑战。我该如何解决?它有可能吗?

4 个答案:

答案 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 
             }