在 Swift 中声明具有类型约束的属性

Posted

技术标签:

【中文标题】在 Swift 中声明具有类型约束的属性【英文标题】:Declaring a Property with Type Constraint in Swift 【发布时间】:2016-03-20 12:40:23 【问题描述】:

我需要在我的应用程序中创建一个自定义字段框架。我为名为@9​​87654321@ 的字段定义了一个协议,并用它扩展了UITextFieldUIButton 为不同类型的字段。

现在我想为字段创建一个容器视图,因此我希望容器能够将其字段元素同时引用为UIViews 和FieldTypes,我想知道是否有简洁的方法将其接收的元素类型定义为实现FieldType 协议的特定UIView

我可以让FieldContainerView 接受UIViews 或FieldTypes 并手动检查它是否也与另一个与guard 语句匹配,但感觉有点麻烦。

我尝试了两种方法:

1) 定义自定义中介FieldViewType

这个想法是让FieldViewType 直接用FieldType 扩展UIView,因此它可能对UITextField: FieldTypeUIButton: FieldType 的一般情况有用。但是正如这个代码示例清楚地表明,这是行不通的。

protocol FieldType 
  var showError: Bool  get set 
  var isEmpty: Bool  get set 


class CustomTextField: UITextField, FieldType 
class CustomButtonField: UIButton, FieldType 

let textField = CustomTextField()
textField is UIView       // True
textField is FieldType    // True

let buttonField = CustomButtonField()
buttonField is UIView     // True
buttonField is FieldType  // True

class FieldView: UIView, FieldProtocol 

let field = FieldView()
field is UIView           // True
field is FieldProtocol    // True

textField is FieldView    // False
buttonField is FieldView  // False

2) 使用泛型

我可以定义一个符合<FieldViewType: UIView where FieldViewType: FieldType> 等要求的泛型类型,但我不知道在哪里可以最好地解决我的问题。如果我在类级别定义它

class FieldContainerView<FieldViewType: UIView where FieldViewType: FieldType>: UIView 
  var fields = [FieldViewType]()
  func addField(FieldViewType: field) 
    fields.append(field)
  

我需要为我要使用的每种字段类型声明一次容器类,并且不能在同一个容器中使用两种字段类型。

另一种选择是使用addField在函数级别定义类型约束

class FieldContainerView: UIView 
  var fields = [UIView]()
  func addField<FieldViewType: UIView where FieldViewType: FieldType>(FieldViewType: field) 
    fields.append(field)
  

然后在必要时将fields 中的每个元素转换为FieldType,我知道转换将始终有效,因为addField 是将元素添加到容器的唯一方法。但这也感觉太麻烦了。

感觉最好的解决方法是能够用typealias 定义FieldViewType,但这似乎不受支持。或者使用协议定义UIView,以便更好地混合,但 UIKit 不是以这种方式构造的。

【问题讨论】:

FieldType 真的是一个空协议吗?如果没有,它实际上是什么?你能发布实际 FieldType 协议吗? 添加了实现。后面可能还有其他东西。 【参考方案1】:

因此,目前似乎没有办法在属性声明中创建类型约束。我不知道为什么,但我对语言实现一无所知。

我找到了一种解决方法,其中FieldType 也有一个默认实现的view: UIView 属性。

新的FieldType 声明:

protocol FieldType 
  var showError: Bool  get set 
  var isEmpty: Bool  get set 
  var view: UIView  get 


extension FieldType where Self: UIView 
  var view: UIView 
    return self
  

这样,在遵守FieldType 协议之前,您从 UIKit 层次结构中的哪个类继承并不重要,只要您在某处将UIView 作为您的超类,您将拥有一个可访问的@987654327 @属性。

这感觉像是一种解决方法,但至少它为需要对象的FieldTypeUIView 属性的集合节省了双重声明。

【讨论】:

以上是关于在 Swift 中声明具有类型约束的属性的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中覆盖具有不同类型的超类属性

在 Swift 中继承具有自己类型和存储属性的数组

“计算属性必须具有显式类型”错误:如何在 Swift 2.x 中列出文件? [复制]

具有自定义类类型的 Swift CoreData 保存属性

在 Swift 中声明任何类型的数组时使用未声明的类型“T”

在具有 C++ 中另一个类型的类中声明属性 [重复]