2016-11-24 29 views
1

我正在努力学习swift并希望使用面向协议的编程方法。我想要实现的很简单,但我找不到任何方法。ios swift class conforming protocol

可以说我有Outlet这是textfield。我希望textfield符合像ValidatesName协议这样的协议。有什么办法可以做到吗? 我不想创建UITextField的子类并遵守协议。我想用这个特定的属性。

@IBOutlet weak var nameTextField:UITextField!<Conforms ValidatesName> 
@IBOutlet weak var emailTextField:UITextField!<Conforms ValidatesEmail> 
@IBOutlet weak var passwordTextField:UITextField!<Conforms ValidatesPassword> 

感谢

+0

但问题是,UITextField类不符合你的期望的协议,该协议采用基于实施Ø f在协议中定义的方法和属性 –

+0

如果我理解正确,我已经可以定义一些像这样的方法。我认为我可以为变量做到这一点。 > – kekkeme

回答

3

您的问题是,尽管您可以通过扩展添加协议一致性,但扩展应用于该类,而不是该类的一个实例。这意味着,你可以这样说:

extension UITextField: ValidatesName {...} 

但是,这将使的UITextField的所有实例符合ValidatesName

同样,你也可以说

extension UITextField: ValidatesEmail{...} 

但现在所有 UITextField的实例将符合ValidatesNameValidatesEmail

拥有单独的Validates...协议似乎不是正确的方法。协议的基本签名是类似于var isValid: Bool;这在姓名和电子邮件之间不会改变。什么是变化是验证逻辑,这必须住在某个地方。这一点,加上你需要使用子类来与Interface Builder一起工作的事实表明,可以由你的各种子类采用的单一协议Validatable是一种更合理的方法。现在

protocol Validatable { 
    var isValid: Bool { get } 
} 

,您可以定义符合本协议的UITextField的子类(你可以,如果你想通过添加扩展的符合你的子类,我只是想在这里保存空间)

class NameTextField: UITextField, Validatable { 

    var isValid: Bool { 
     get { 
      guard let text = self.text else { 
       return false 
      } 

      return !text.isEmpty 
     } 
    } 
} 

class EmailTextField: UITextField, Validatable { 
    var isValid: Bool { 
     get { 
      guard let text = self.text else { 
       return false 
      } 

      return text.contains("@") 
     } 
    } 
} 

现在,您可以添加文本框到一个数组中,并有类似:

@IBOutlet weak var nameTextField:NameTextField! 
@IBOutlet weak var emailTextField:EmailTextField! 

var validatableFields:[Validatable]! 

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.validatableFields = [nameTextField,emailTextField] 
} 

... 

for field in validateableFields { 
    if !field.isValid() { 
     print("A field isn't valid") 
    } 
} 
+0

如何将IBOutletCollection数组类型编写为只有协议,我试过但我得到错误。如果尝试将其作为[ProtocolName]实现,则会出现错误。 – kekkeme

+0

你说得对,对不起。我更新了我的答案。您需要自己构建阵列。这是Objective-C的遗留限制你在Swift中可以做的事情的地方之一。 – Paulw11

+0

这是使用它们作为数组来防止viewcontroller内部很多守卫的好答案。只有我会改变的是nameTextField和emailTextField是视图。他们不是主持人(MVP),他们不是视图模型(MVVM),所以我会做一点改变,但是感谢validatableFields的想法。 – kekkeme

1

不幸的是有一些限制阻止这样的:

  1. IBOutlets必须是指从NSObject的继承,大概要启用存档/解码类,所以你不能仅使用IBOutlet类型的协议

  2. Swift没有办法将变量的类型声明为具体的typ e +协议一致性,你在你的例子中的做法

  3. 在Objective-C中,你可以声明具体的类型+协议一致性,但协议被IBOutlets忽略,可能是因为协议一致性在运行时被检查, Xcode/Interface Builder在设计时不一定知道对象是否最终符合协议。