Swift扩展到MutableCollectionType不使用泛型类型数组

时间:2016-02-27 14:14:18

标签: ios swift generics

我在UIView上有一个扩展,它根据元类型返回一个子视图数组。这样我可以查询视图层次结构,例如所有UITextFields等。

extension UIView {
    func subviewsOfType<T:UIView>(_:T.Type) -> [T]? {
        ...
    }
}

这可以像这样调用:

let fields = loginView.subviewsOfType(UITextField.self)

现在,我想在该数组[UITextField]上使用与传入的泛型相匹配的接口,换句话说,在UITextField上可用的任何内容,例如:

fields.alpha = 0.3 // via UIView
fields.enabled = false // via UIControl

我在MutableCollectionType上创建了扩展程序以提供这些替换:

extension MutableCollectionType where Generator.Element == UIView {

    var alpha:CGFloat {
        get {
            if let first = self.first {
                return first.alpha
            } else {
                return 1.0
            }
        }
        set {
            for view in self {
                view.alpha = newValue
            }
        }
    }
}

extension MutableCollectionType where Generator.Element == UIControl {

    var enabled:Bool {
        get {
            if let first = self.first {
                return first.enabled
            } else {
                return true
            }
        }
        set {
            for view in self {
                view.enabled = newValue
            }
        }
    }
}

但是,当我尝试使用这些扩展时,它们无法按预期工作。 :(

以下是我尝试过的调用代码的变体及其错误:

Ambiguous reference to member alpha

Cannot assign to property fields is let constant

Cannot assign to immutable expression of type

Ambiguous reference to member enabled

或者,我尝试使用方法而不是计算属性,例如

func alpha(alpha:CGFloat) -> Self {
    for view in self {
        view.alpha = alpha
    }
    return self
}

这&#34;工作&#34;但包括丑陋的演员:

Using setters

我更喜欢通过MutableCollectionType扩展程序在这些数组上使用常规属性:

loginView.subviewsOfType(UITextField.self).enabled = true

我错过了什么?

2 个答案:

答案 0 :(得分:4)

您已完全约束UIView,而不是UIView的子类。你的意思是:

extension MutableCollectionType where Generator.Element: UIView { ... }
extension MutableCollectionType where Generator.Element: UIControl { ... }

请注意:而不是==

在这种特殊情况下,您需要fields成为var,因为您要改变它:

if var fields = loginView.subviewsOfType(UITextField.self) {
    fields.alpha = 0.3
    fields.enabled = true
}

答案 1 :(得分:4)

有两个问题。作为Rob already said,您必须限制 UIView / UIControl子类的扩展方法。

然后编译器仍抱怨

if let fields = self.view.subviewsOfType(UITextField.self) {
    fields.alpha = 0.3
    fields.enabled = false
}

error: cannot assign to property: 'fields' is a 'let' constant

原因是设置属性被视为变异 数组(值类型),你不能改变常量。

但是,您的案例中的数组元素本身是引用类型 (班级的实例)。 setter方法只改变引用的对象,并保留 数组本身不变。因此,您可以声明setter方法 作为nonmutating

var alpha:CGFloat {
    get { ... }
    nonmutating set {
        for view in self {
            view.alpha = newValue
        }
    }
}

现在上面的代码编译和工作没有问题。