ios swift类符合协议

时间:2016-11-24 21:06:45

标签: ios swift protocols protocol-oriented

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

让我说我的Outlet是文本字段。我希望textfield符合ValidatesName协议之类的协议。有什么办法吗? 我不想创建子类UITextField并符合协议的新类。我想用于这个特定的属性。

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

由于

2 个答案:

答案 0 :(得分:3)

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

extension UITextField: ValidatesName {...}

但这会使 UITextField的所有实例符合ValidatesName

同样,你也可以说

extension UITextField: ValidatesEmail{...}

但是现在 UITextField的所有实例都符合ValidatesName ValidatesEmail

单独使用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")
    }
}

答案 1 :(得分:1)

不幸的是,有一些限制阻止了这个:

  1. IBOutlets必须引用从NSObject继承的类,可能是为了启用归档/解码,因此您不能只使用IBOutlet类型的协议

  2. Swift无法将变量的类型声明为具体类型+协议一致性的组合,就像您在示例中所做的那样

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