如何在Swift中的递归扩展(类别)函数中传递泛型类类型?

时间:2014-10-30 15:21:49

标签: objective-c generics recursion uiview swift

我想以编程方式更改所有子视图的特定类类型UILabelUITextField等)的文本颜色(不仅仅是直接的孩子,还有那个孩子的孩子等等。

我创建了UIView的扩展程序,以递归方式访问其所有子视图及其子视图。它目前硬编码为更改单一类型(UILabel)的颜色。

这是我得到的代码:

import UIKit

extension UIView {
    func setLabelTextColor(color: UIColor) {
        for subview in self.subviews {
            // Visit any subviews of the current subview (this is the recursive part)
            subview.setLabelTextColor(color)

            // Is this a label?  If so, change it's text color.
            if let label = subview as? UILabel {  <-- I WANT TO PASS THIS CLASS
                label.textColor = color
            }
        }
    }
}


class OptimusPrimeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.setLabelTextColor(UIColor.blueColor())
    }
}

如何在Swift中使用泛型来传递类类型(如UITextField而不是UILabel),这样我就可以指定要更改哪个类'文本颜色?也许有一些块(封闭)魔法可以做同样的事情?

所以而不是:

self.view.setLabelTextColor(UIColor.blueColor())

我有类似的东西:

self.view.setTextColor(UIColor.blueColor(), forClassType: UITextField.self)

2 个答案:

答案 0 :(得分:2)

您可以在函数定义中定义泛型类型T,如下所示:

extension UIView {
    func setTextColor<T: UIView>(color: UIColor, forClassType _: T.Type) {
        for subview in self.subviews as [UIView] {
            subview.setTextColor(color, forClassType: T.self)

            if let view = subview as? T {
                view.textColor = color
            }
        }
    }
}

但是,textColor不是所有UIView的属性,因此您需要更进一步。一种解决方案是定义具有textColor属性的协议,然后声明UILabelUITextField以及要与此函数一起使用的任何其他类的协议一致性。如果该类尚未定义textColor属性,则需要将其添加到扩展名中。

所以这是完整的代码:

protocol HasTextColor {
    var textColor: UIColor! { get set }
}

extension UILabel: HasTextColor {}
extension UITextField: HasTextColor {}

extension UIView {
    func setTextColor<T: UIView where T: HasTextColor>(color: UIColor, forClassType _: T.Type) {
        for subview in self.subviews as [UIView] {
            subview.setTextColor(color, forClassType: T.self)

            if let view = subview as? T {
                view.textColor = color
            }
        }
    }
}

您可以完全按照建议调用此函数:

self.view.setTextColor(UIColor.blueColor(), forClassType: UITextField.self)

答案 1 :(得分:0)

我想我找到了一种方法来做到这一点,而不必使用协议,并且必须明确地将每个类符合该协议,以便他们可以使用此功能。

相反,它使用NOSbject内省来查看视图是否是正确的类型并具有该属性。这样我可以将它与任何具有textColor的东西一起使用,并且不必添加任何代码。

func setGlobalTextColor<T: NSObject>(color: UIColor, forClassType: T.Type) {
    for subview in self.subviews as [UIView]{

        // Visit every child before applying changes
        subview.setGlobalTextColor(color, forClassType: T.self)

        // Only change text color for the class we called the function with
        if subview.isMemberOfClass(T) {

            // Sanity check to make sure we only set if class has this property
            if subview.respondsToSelector(Selector("textColor")) {

                // Use Key Value Coding to set the textColor        
                subview.setValue(color, forKey: "textColor")
            }
        }
    }
}

因此,您可以使用具有UIColor textColor属性的不同类来调用它:

self.view.setTextColor(UIColor.blueColor(), forClassType: UILabel.self)
self.view.setTextColor(UIColor.redColor(), forClassType: UITextField.self)