首页 文章

ios swift类符合协议

提问于
浏览
1

我正在努力学习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 回答

  • 1

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

    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")
        }
    }
    
  • 3

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

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

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

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

相关问题