1

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

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

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

谢谢

4

2 回答 2

3

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

extension UITextField: ValidatesName {...}

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

同样,你也可以说

extension UITextField: ValidatesEmail{...}

但是现在UITextField 的所有实例都将符合ValidatesName and 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")
    }
}
于 2016-11-24T21:59:47.843 回答
1

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

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

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

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

于 2016-11-24T21:43:25.737 回答