ios swift class 符合协议
ios swift class conforming protocol
我正在努力学习 swift 并且想使用面向协议的编程方法。我想要实现的目标很简单,但我找不到任何方法。
假设我有 Outlet,它是文本字段。我希望该文本字段符合 ValidatesName 协议之类的协议。有什么办法吗?
我不想创建 new class which subclass UITextField 并符合协议。我想用于这个特定的 属性。
@IBOutlet weak var nameTextField:UITextField!<Conforms ValidatesName>
@IBOutlet weak var emailTextField:UITextField!<Conforms ValidatesEmail>
@IBOutlet weak var passwordTextField:UITextField!<Conforms ValidatesPassword>
谢谢
不幸的是,有一些限制阻止了这一点:
IBOutlets 必须引用继承自 NSObject 的 类,可能是为了启用存档/解码,因此您不能仅使用 IBOutlet 类型的协议
在 Swift 中无法将变量的类型声明为具体类型 + 协议一致性的组合,就像您在示例中所做的那样
在Objective-C中你可以声明具体类型+协议一致性,但是IBOutlets无论如何都会忽略协议,可能是因为协议一致性是在运行时检查的,它不一定是已知的Xcode / Interface Builder 在设计时一个对象是否最终会符合一个协议。
您的问题是,虽然您可以通过扩展添加协议一致性,但扩展应用于 class,而不是 class 的实例。这意味着您可以这样说:
extension UITextField: ValidatesName {...}
但这将使 所有 个 UITextField 实例符合 ValidatesName
同样,你也可以说
extension UITextField: ValidatesEmail{...}
但现在 所有 UITextField 实例将符合 ValidatesName
和 ValidatesEmail
.
拥有单独的 Validates...
协议似乎无论如何都不是正确的方法。您的协议的基本签名类似于 var isValid: Bool
;这在姓名和电子邮件之间不会改变。真正改变的是验证逻辑,它必须存在于某个地方。这一点,再加上您需要 subclasses 才能与 Interface Builder 一起工作的事实,建议您的各种 subclasses 可以采用的单一协议 Validatable
是一个更合理的做法。
protocol Validatable {
var isValid: Bool { get }
}
现在,您可以定义符合此协议的 UITextField 的子classes(如果您愿意,可以通过扩展将一致性添加到子class,我只是想保存space 这里)
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")
}
}
我正在努力学习 swift 并且想使用面向协议的编程方法。我想要实现的目标很简单,但我找不到任何方法。
假设我有 Outlet,它是文本字段。我希望该文本字段符合 ValidatesName 协议之类的协议。有什么办法吗? 我不想创建 new class which subclass UITextField 并符合协议。我想用于这个特定的 属性。
@IBOutlet weak var nameTextField:UITextField!<Conforms ValidatesName>
@IBOutlet weak var emailTextField:UITextField!<Conforms ValidatesEmail>
@IBOutlet weak var passwordTextField:UITextField!<Conforms ValidatesPassword>
谢谢
不幸的是,有一些限制阻止了这一点:
IBOutlets 必须引用继承自 NSObject 的 类,可能是为了启用存档/解码,因此您不能仅使用 IBOutlet 类型的协议
在 Swift 中无法将变量的类型声明为具体类型 + 协议一致性的组合,就像您在示例中所做的那样
在Objective-C中你可以声明具体类型+协议一致性,但是IBOutlets无论如何都会忽略协议,可能是因为协议一致性是在运行时检查的,它不一定是已知的Xcode / Interface Builder 在设计时一个对象是否最终会符合一个协议。
您的问题是,虽然您可以通过扩展添加协议一致性,但扩展应用于 class,而不是 class 的实例。这意味着您可以这样说:
extension UITextField: ValidatesName {...}
但这将使 所有 个 UITextField 实例符合 ValidatesName
同样,你也可以说
extension UITextField: ValidatesEmail{...}
但现在 所有 UITextField 实例将符合 ValidatesName
和 ValidatesEmail
.
拥有单独的 Validates...
协议似乎无论如何都不是正确的方法。您的协议的基本签名类似于 var isValid: Bool
;这在姓名和电子邮件之间不会改变。真正改变的是验证逻辑,它必须存在于某个地方。这一点,再加上您需要 subclasses 才能与 Interface Builder 一起工作的事实,建议您的各种 subclasses 可以采用的单一协议 Validatable
是一个更合理的做法。
protocol Validatable {
var isValid: Bool { get }
}
现在,您可以定义符合此协议的 UITextField 的子classes(如果您愿意,可以通过扩展将一致性添加到子class,我只是想保存space 这里)
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")
}
}