iOS现场验证-快速简便

图片输入字段的验证可能是移动应用程序中最常见的任务。每个采用授权和注册形式的应用程序还具有来自用户的一定量的输入信息,这引起了预期的悲伤-测试人员的复杂兴奋。一个高级的,技术精湛的开发人员社区已经学习了如何通过在源代码中嵌入正则表达式有效地处理它们

通常,当您需要限制自己的注册和授权时,无需付出特殊的努力即可实现目标-代码从一个项目转移到另一个项目,几乎没有任何更改。而且,最重要的是,在不增加进一步维护此代码的工时的情况下。但是,如果不是因为UI / UX设计师的创新冲动,他们倾向于与既定的传统,逻辑和常识相反,而是发明与最终用户进行交互的新方式,并在他们看来,将几种必要的控件,可访问性放在表格上,那么世界就不会那么简单了。这取决于用于检查大量输入字段和其他控制控件的有效性的笛卡尔条件集。不幸的是,这种情况很难被称为罕见。

开发人员对自己违反DRY原则的频率的提高与之成正比:一方面,专业自豪感不允许妥协;另一方面,复制粘贴代码是避免长测试周期(调试)的最有效方法。单调的复制代码比经过思想验证的唯一“自行车”容易维护。寻找替代品不仅浪费开发人员的创造力,而且还增加了对项目的依赖性。

同时,iOS SDK提供了一些被低估的功能,这些功能可以轻松扩展到不仅与验证有关的许多任务-声明式编程极大地简化了开发人员的工作。当然,作者知道恋人的阵营是使用“未稀释”代码的朋友,但是自从本文的作者开始通过为MS DOS开发图形用户界面来开发专业界面时,就没有很大的浪费时间来创建另一个完美的类的愿望,并且如果您可以同等价值地使用它,鼠标-将优先使用鼠标。因此,它概述了如何最大程度地减少代码量以加快和简化开发过程。

免责声明:
, . . , — .

典型的最小任务如下:

有登录和密码输入字段,以及一个授权按钮。授权按钮必须根据输入字段中包含的内容更改状态(isEnable)。

此任务的高级版本如下所示:

我们具有电子邮件,密码和电话号码输入字段,以及两个按钮-注册和请求输入电话的SMS代码。仅当在每个字段中输入正确的数据时,注册按钮才可用。当电话号码字段有效时,代码请求按钮才可用。

典型解决方案-通过在一个视图控制器中组合“ if”和“ switch”语句来创建相互依赖的标志。难度将随着过程中涉及的控制数量而增加。一个更高级的解决方案是创建状态机。该解决方案非常好-但是很耗时,而且入口门槛很高-这绝不是我想对懒惰(又名“真实”)开发人员实施的解决方案。

关于懒惰的开发人员的Lema
, , . (« » ), , .

提出的总体思路如下:

输入字段有一个类,验证管理器有一个类。如预期的那样,输入字段继承自UITextField。验证管理器-继承自UIControl,包含一组经过验证的元素(完全不需要成为UITextField的后代),并实现“观察者”模式。此外,他还担任其他控件的管理者,这些控件在已验证元素的状态更改时必须更改其可访问性状态。换句话说,如果该字段包含无效的电子邮件,则注册按钮应该不可用。



输入字段是自验证的-它们可以回答包含在其中的数据是否有效并更改其状态的问题。一些开发人员更喜欢使用单独的验证器类(及其后代)来验证输入字段,但是这种做法使得无法完全享受代码的声明性和可伸缩性的可移植性。对我们而言,输入字段或任何其他经过验证的控件支持以下形式的简单接口对我们很重要:

@objc protocol IValidatable : class {
    varisValid: Bool { get }
}

要向您的项目添加验证,您需要从GitHub存储库中的示例中添加4个文件

  • DSTextField实现一个带有验证过程指示的输入字段。
  • DSValidationManager是提供我们所需功能的观察者。
  • 扩展StringOptional + Utils-仅包含一种使用正则表达式检查当前行文本是否有效的方法。
  • UIView + Layer是将给定宽度的框架添加到UIView的任何后代的便捷方法。

严格来说,如果要对任何其他控件以相同的方式实现验证,则很可能只需要DSValidationManager。其余仅用于您的方便。

验证过程显示在视频(gif)中。


如您所见,在输入开始之前,该字段处于默认状态,并且在输入数据时进行验证。如果您在验证完成之前离开该字段,则会在该字段上显示题字,告知错误。在两个字段都变为有效之前,注册按钮将不可用。

在第二个屏幕上也会出现类似情况(仅在激活注册后才可用)。但是在第二个屏幕上,字段和按钮的验证是独立进行的-仅当所有字段都失败时,注册按钮才可用。同时,当带有电话号码的字段有效时,SMS发送按钮已经可用。

现在的诀窍是:整个项目只包含一个视图控制器类,与从模板创建项目时Xcode创建的类相同。它是完全空的。但即使不使用。在调度员的帮助下验证这一点并不困难。



细心的读者注意到,响应者的右边是标准Xcode组件面板中的Object。为此,Class参数被DSValidationManager class覆盖对输入字段进行了相同的技巧,唯一的区别是在那里使用了DSTextField

现在,我们所有的编程都归结为以下简单步骤:

  1. 将ValidationManager中的verifyControls集合与输入字段相关联。


  2. 将ValidationManager中的managedControls集合与您要管理的按钮相关联。


  3. 将相反方向的输入字段与ValidationManager关联,使其成为委托。

  4. 在输入字段中,通过标准Xcode管理器设置用于验证的正则表达式和错误消息,以及其他自定义和标准属性。原则上,除正则表达式外的所有内容都可以“按原样”保留。它只需要您使用键盘,然后只需从tyrnet复制粘贴公式即可。如果错误消息丢失,那么它将根本不会显示在屏幕上。


DSValidationManager 代码很丑陋。

import UIKit

@objc protocol IValidationManager : class {
    func verificated()
}

@objc protocol IValidatable : class {
    var isValid: Bool { get }
}

class DSValidationManager : UIControl, IValidationManager
{
    @IBOutlet var verifiedControls: [UIControl]?
    @IBOutlet var managedControls: [UIControl]?

    private (set) var valid : Bool = false {
        didSet {
            self.sendActions(for: .valueChanged)
        }
    }
    
    overrideinit(frame: CGRect) {
        super.init(frame: frame)
        self.verificated()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.verificated()
    }

    func verificated() {
        self.checkVerifiedControls()
        self.controlsAction()
    }

    private func checkVerifiedControls() {
        guard let list:[IValidatable] = self.verifiedControls?.filter({$0 isIValidatable}) as? [IValidatable]
            else { return }
        self.valid = list.filter({!$0.isValid}).count==0
    }
    
    private func controls Action() {
        guard let list = self.managedControls else { return }
        for item in list {
            item.isEnabled = self.valid
        }
    }
}

如您所见,他从一个集合中收到通知,然后对另一个集合进行操作。

观察者将其设为在本示例中甚至没有考虑的属性。您可以将连接从ValidationManager对象直接拖动到控制器,在其中添加类似于单击按钮的事件,然后直接在控制器中处理经理的状态。如果您真的想要。如果您不仅应该锁定控件,而且还要做一些有用的工作(例如,进行游行或显示AlertView),这将很有用。

在所有TextEdit代码中,仅应注意,该字段必须注意正确设置“ isValid属性,并拉出“ verify()方法”“来自他的代表。但是,请注意,输入字段不使用对管理器对象的引用,而是一个集合。这使您可以将输入字段绑定到多个管理器。

因此,该方法将需要由每个代表来提出。

    var isValid: Bool {
        return self.text.verification(self.expression, required:self.valueRequired)
    }

    @IBOutlet var validateDelegates: [IValidationManager]?

    private func handleDelegateAction(_ sender: UITextField) {
        guard let list = self.validateDelegates else { return }

        for validateDelegate in list {
            validateDelegate.verificated()
        }
    }

现在,如果您需要使用输入字段组成一个新表单,甚至不需要设置自定义属性值-只需批量复制所需的Runtime属性并将其应用于新字段就足够了(不要忘记仅替换类名)。


一般而言,在表单标题中使用“对象”的技巧可以广泛使用,而不仅仅是用于字段验证-它可以将MVC反应性地转换为MVVM,而无需任何Rx。它最常见的用途是网络共享和CoreData模型更改通知。

All Articles