ios swift类一致性协议

ios swift类一致性协议,ios,swift,protocols,protocol-oriented,Ios,Swift,Protocols,Protocol Oriented,我正在努力学习swift,并希望使用面向协议的编程方法。我想要实现的很简单,但我找不到任何方法 假设我有一个出口,它是textfield。我希望textfield符合类似ValidateName协议的协议。有什么办法吗? 我不想创建一个新类,它是UITextField的子类,并且符合协议。我想用这个特殊的属性 @IBOutlet weak var nameTextField:UITextField!<Conforms ValidatesName> @IBOutlet weak var

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

假设我有一个出口,它是textfield。我希望textfield符合类似ValidateName协议的协议。有什么办法吗? 我不想创建一个新类,它是UITextField的子类,并且符合协议。我想用这个特殊的属性

@IBOutlet weak var nameTextField:UITextField!<Conforms ValidatesName>
@IBOutlet weak var emailTextField:UITextField!<Conforms ValidatesEmail>
@IBOutlet weak var passwordTextField:UITextField!<Conforms ValidatesPassword>
@ibextfield:UITextField!
@IBOutlet弱var emailTextField:UITextField!
@IBOutlet弱var密码文本字段:UITextField!

谢谢

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

  • IBOutlet必须引用从NSObject继承的类,可能是为了启用归档/解码,所以不能只对IBOutlet的类型使用协议

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

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


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

  • IBOutlet必须引用从NSObject继承的类,可能是为了启用归档/解码,所以不能只对IBOutlet的类型使用协议

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

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


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

    extension UITextField: ValidatesName {...}
    
    @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")
        }
    }
    
    但这将使UITextField的所有实例符合
    ValidatesName

    同样,你也可以说

    extension UITextField: ValidatesEmail{...}
    
    但是现在UITextField的所有实例都将符合
    validateName
    validateMail

    使用单独的
    验证…
    协议似乎不是正确的方法。协议的基本签名类似于
    var isValid:Bool
    ;这不会在姓名和电子邮件之间更改。改变的是验证逻辑,它必须存在于某个地方。这一点,再加上您需要子类才能使用Interface Builder这一事实,表明可以由各种子类采用的单个协议
    Validatable
    是一种更合理的方法

    protocol Validatable  {
        var isValid: Bool { get }
    }
    
    现在,您可以定义符合此协议的UITextField子类(如果愿意,您可以通过子类的扩展添加一致性,我只是想在这里节省空间)

    现在,您可以将文本字段添加到数组中,并具有如下内容:

    extension UITextField: ValidatesName {...}
    
    @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")
        }
    }
    

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

    extension UITextField: ValidatesName {...}
    
    @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")
        }
    }
    
    但这将使UITextField的所有实例符合
    ValidatesName

    同样,你也可以说

    extension UITextField: ValidatesEmail{...}
    
    但是现在UITextField的所有实例都将符合
    validateName
    validateMail

    使用单独的
    验证…
    协议似乎不是正确的方法。协议的基本签名类似于
    var isValid:Bool
    ;这不会在姓名和电子邮件之间更改。改变的是验证逻辑,它必须存在于某个地方。这一点,再加上您需要子类才能使用Interface Builder这一事实,表明可以由各种子类采用的单个协议
    Validatable
    是一种更合理的方法

    protocol Validatable  {
        var isValid: Bool { get }
    }
    
    现在,您可以定义符合此协议的UITextField子类(如果愿意,您可以通过子类的扩展添加一致性,我只是想在这里节省空间)

    现在,您可以将文本字段添加到数组中,并具有如下内容:

    extension UITextField: ValidatesName {...}
    
    @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")
        }
    }
    

    但是问题是UITextField类不符合您想要的协议,协议的采用是基于协议中定义的方法和属性的实现。如果我理解正确,我已经可以定义这样的方法了。我想我可以为变量做这件事。>但是问题是UITextField类不符合您想要的协议,协议的采用是基于协议中定义的方法和属性的实现。如果我理解正确,我已经可以定义这样的方法了。我想我可以为变量做这件事。>如何将IBOutletCollection数组类型编写为唯一的协议,我尝试过,但遇到了错误。如果尝试将其实现为[ProtocolName],则会出现错误。您是对的,抱歉。我更新了我的答案。您需要自己构建阵列。这是Objective-C的传统限制了您在Swift中所能做的事情的地方之一。这是一个很好的答案,可以将它们用作阵列,以防止viewcontroller中出现大量警卫。我唯一要更改的是nameTextField和emailTextField是视图。它们不是presenter(MVP),也不是view model(MVVM),因此我将对其进行一些更改,但要感谢validatableFields的想法。我如何才能将IBMoutletCollection数组类型编写为唯一的协议,我尝试了,但出现了错误。如果尝试将其实现为[ProtocolName],则会出现错误。您是对的,抱歉。