[英]Swift extension to MutableCollectionType not working with array of generic types
I have an extension on UIView that returns an array of sub-views based on meta type. 我在UIView上有一个扩展,它根据元类型返回一个子视图数组。 This way I can query the view hierarchy for example for all UITextFields, etc.
这样我可以查询视图层次结构,例如所有UITextFields等。
extension UIView {
func subviewsOfType<T:UIView>(_:T.Type) -> [T]? {
...
}
}
This can be called like so: 这可以像这样调用:
let fields = loginView.subviewsOfType(UITextField.self)
Now, I would like to act on that array [UITextField]
with an interface that matches the generic passed in, in other words whatever is available on UITextField, example: 现在,我想在该数组
[UITextField]
使用与传入的泛型相匹配的接口,换句话说,UITextField上可用的任何内容,例如:
fields.alpha = 0.3 // via UIView
fields.enabled = false // via UIControl
I have created extensions on MutableCollectionType
to provide these overrides: 我在
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
}
}
}
}
However, when I try to use these extensions they do not work as expected. 但是,当我尝试使用这些扩展时,它们无法按预期工作。 :(
:(
Here are the variations of calling code I have tried and their errors: 以下是我尝试过的调用代码的变体及其错误:
Alternatively, I tried using methods instead of computed properties, eg 或者,我尝试使用方法而不是计算属性,例如
func alpha(alpha:CGFloat) -> Self {
for view in self {
view.alpha = alpha
}
return self
}
This "works" but includes ugly casting: 这“有效”,但包括难看的铸造:
I would prefer to use regular properties on those arrays via the MutableCollectionType
extensions: 我更喜欢通过
MutableCollectionType
扩展在这些数组上使用常规属性:
loginView.subviewsOfType(UITextField.self).enabled = true
What am I missing?? 我错过了什么?
You've constrained to exactly UIView
, not subclasses of UIView
. 你已经完全限制了
UIView
,而不是UIView
子类。 You meant this: 你的意思是:
extension MutableCollectionType where Generator.Element: UIView { ... }
extension MutableCollectionType where Generator.Element: UIControl { ... }
Note the :
rather than ==
. 注意
:
而不是==
。
And in this particular case, you'll need fields
to be a var
since you mutate it: 在这种特殊情况下,您需要将
fields
变为var
因为您将其变异:
if var fields = loginView.subviewsOfType(UITextField.self) {
fields.alpha = 0.3
fields.enabled = true
}
There are two problems. 有两个问题。 As Rob already said , you have to restrict the extension methods to subclasses of
UIView
/ UIControl
. 正如Rob已经说过的 ,你必须将扩展方法限制为
UIView
/ UIControl
子类 。
But then the compiler still complains on 但随后编译器仍抱怨
if let fields = self.view.subviewsOfType(UITextField.self) {
fields.alpha = 0.3
fields.enabled = false
}
with 同
error: cannot assign to property: 'fields' is a 'let' constant
The reason is that setting a property is considered a mutation of the array (which is a value type ), and you cannot mutate constants. 原因是设置属性被认为是数组的变异 (这是一种值类型 ),并且您不能改变常量。
However, the array elements itself in your case are reference types (instances of a class). 但是,在您的情况下,数组元素本身是引用类型 (类的实例)。 The setter methods mutate only the referenced objects, and leave the array itself unchanged.
setter方法只改变引用的对象,并保持数组本身不变。 Therefore you can declare the setter method as
nonmutating
: 因此,您可以将setter方法声明
nonmutating
:
var alpha:CGFloat {
get { ... }
nonmutating set {
for view in self {
view.alpha = newValue
}
}
}
And now the above code compiles and works without problems. 现在上面的代码编译和工作没有问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.