Validación de campo IOS: rápida y fácil

imagenLa validación de los campos de entrada es quizás la tarea más común en las aplicaciones móviles. Cada aplicación que toma la forma de autorización y registro también tiene una serie de herramientas de entrada del usuario, que dan lugar a la esperada y sofisticada emoción sádica de los evaluadores. Una comunidad avanzada, técnicamente competentes de los desarrolladores ha aprendido a lidiar efectivamente con ellos mediante la incorporación de expresiones regulares en el código fuente.

Como regla general, cuando necesita limitarse al registro y la autorización, no necesita hacer esfuerzos especiales para lograr su objetivo: el código se transfiere de un proyecto a otro, casi sin ningún cambio. Y, lo más importante, sin aumentar las horas hombre para un mayor mantenimiento de este código. Pero el mundo no sería tan simple si no fuera por los impulsos creativos de los diseñadores de UI / UX que se inclinan, contrariamente a la tradición establecida, la lógica y el sentido común, a inventar nuevas formas de interactuar con el usuario final, colocando en el formulario varios, en su opinión, controles necesarios, accesibilidad que depende del conjunto de condiciones cartesianas para verificar la validez de un gran número de campos de entrada y otros controles de control. Desafortunadamente, esta situación difícilmente se puede llamar rara.

La irritación del desarrollador crece en proporción a la frecuencia con la que tiene que violar los principios DRY: por un lado, el orgullo profesional no permite compromisos, y por otro, el código de copiar y pegar es la forma más efectiva de evitar un ciclo de prueba largo: la depuración. El código copiado monótono es mucho más fácil de mantener que la "bicicleta" única ideológicamente verificada. La búsqueda de una alternativa no solo desperdicia la creatividad del desarrollador, sino que también agrega dependencias al proyecto.

Al mismo tiempo, el SDK de iOS presenta algunas características extremadamente subestimadas que se adaptan fácilmente a muchas tareas relacionadas no solo con la validación: la programación declarativa simplifica enormemente la vida del desarrollador. Por supuesto, el autor conoce el implacable campamento de amantes.amigos del uso de código "sin diluir", pero dado que el autor del artículo comenzó a desarrollar interfaces profesionales mediante el desarrollo de una interfaz gráfica de usuario para MS DOS, no hay un gran deseo de perder el tiempo creando otra clase perfecta, y si puede usarla con el mismo valor mouse: se dará preferencia al mouse. En consecuencia, describe cómo minimizar la cantidad de código para acelerar y simplificar el proceso de desarrollo.

Descargo de responsabilidad:
, . . , — .

Una tarea mínima típica es la siguiente:

hay campos de entrada y contraseña de ingreso, y un botón de autorización. Es necesario que el botón de autorización cambie de estado (isEnable) según lo que contengan los campos de entrada.

Una versión un poco más avanzada de esta tarea se ve así:

tenemos los campos de entrada de correo electrónico, contraseña y número de teléfono, así como dos botones: registro y solicitud de un código SMS para el teléfono ingresado. El botón de registro solo debe estar disponible cuando se ingresan los datos correctos en cada uno de los campos. Y el botón de solicitud de código es cuando el campo del número de teléfono es válido.

Solución típica- creación de banderas interdependientes combinando las declaraciones "if" y "switch" en un controlador de vista. La dificultad aumentará con la cantidad de controles involucrados en el proceso. Una solución mucho más avanzada sería crear una máquina de estados. La solución es excelente, pero requiere mucho tiempo, además de tener un umbral de entrada alto, y esto no es lo que quiero implementar para el desarrollador perezoso (también conocido como "verdadero").

Lema sobre un desarrollador perezoso
, , . (« » ), , .

La idea general de la propuesta es la siguiente:

hay una clase para el campo de entrada y una clase para el administrador de validación. El campo de entrada se hereda, como se esperaba, de UITextField. Administrador de validación: heredado de UIControl, contiene una colección de elementos validados (no es necesario ser descendientes de UITextField) e implementa el patrón de "observador". Además, actúa como administrador de otros controles que deben cambiar su estado de accesibilidad cuando cambia el estado de los elementos validados. En otras palabras, si el campo contiene un correo electrónico no válido, el botón de registro no debería estar disponible.



Los campos de entrada se autovalidan: pueden responder a la pregunta de si los datos contenidos en ellos son válidos y cambiar su estado. Algunos desarrolladores prefieren usar una clase de validador separada (y sus descendientes) para validar los campos de entrada, pero esta práctica hace que sea imposible disfrutar plenamente de la portabilidad declarativa y escalable del código. Es importante para nosotros que el campo de entrada o cualquier otro control validado admita una interfaz simple del formulario:

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

Para agregar validación a su proyecto, debe agregar 4 archivos del ejemplo ubicado en el repositorio de GitHub .

  • La clase DSTextField implementa un campo de entrada con una indicación del proceso de validación.
  • La clase DSValidationManager es un observador que proporciona la funcionalidad que necesitamos.
  • Extension StringOptional + Utils : contiene solo un método que usa una expresión regular para verificar si el texto de la línea actual es válido.
  • UIView + Layer es solo una forma conveniente de agregar un marco de un ancho dado a cualquier descendiente de UIView.

Estrictamente hablando, si desea implementar la validación de la misma manera para cualquier otro control, lo más probable es que solo necesite el DSValidationManager. El resto se usa solo para su conveniencia.

El proceso de validación se muestra en el video (gif).


Como puede ver, antes de que comience la entrada, el campo está en estado predeterminado y la validación se produce a medida que se ingresan los datos. Si abandona el campo antes de que se complete la validación, aparece una inscripción en el campo que notifica el error. El botón de registro no estará disponible hasta que ambos campos sean válidos.

Una situación similar se desarrolla en la segunda pantalla (que está disponible solo después de la activación del registro). Pero en la segunda pantalla, la validación de los campos y botones se realiza de forma independiente: el botón de registro solo está disponible si todos los campos han fallado. Al mismo tiempo, el botón de envío de SMS ya está disponible cuando el campo con el número de teléfono es válido.

Y ahora el truco:Todo el proyecto contiene solo una clase para el controlador de vista, la misma que Xcode creó al crear el proyecto desde la plantilla. Esta completamente vacio. Pero incluso no se usa. Esto no es difícil de verificar con la ayuda del despachador.



Un lector atento notó que a la derecha del respondedor hay un Objeto de la paleta de componentes Xcode estándar. Para ello, la clase DSValidationManager anula el parámetro Class . Se hizo el mismo truco para los campos de entrada, con la única diferencia de que la clase DSTextField se usa allí .

Ahora toda nuestra programación se reduce a los siguientes pasos simples:

  1. Asociar la colección VerifiedControls del ValidationManager con los campos de entrada.


  2. Asociar la colección managedControls de ValidationManager con el botón que desea administrar.


  3. Asocia campos de entrada en la dirección opuesta con el ValidationManager, convirtiéndolo en un delegado.

  4. En el campo de entrada, establezca una expresión regular para la validación y un mensaje de error, así como otras propiedades personalizadas y estándar a través del administrador Xcode estándar. En principio, todo excepto la expresión regular se puede dejar "como está". Solo requiere que use el teclado, y luego, solo para copiar y pegar la fórmula de tyrnet. Si falta el mensaje de error, simplemente no se mostrará en la pantalla.


El código DSValidationManager es feo primitivo.

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
        }
    }
}

Como puede ver, recibe una notificación de una colección y actúa en otra.

Un observador lo convierte en una propiedad que ni siquiera consideramos en este ejemplo. Puede arrastrar la conexión desde el objeto ValidationManager directamente al controlador, agregar un evento allí similar a hacer clic en un botón y procesar el estado del administrador directamente en el controlador. Si realmente lo quieres. Esto puede ser útil si no solo debe bloquear el control, sino también hacer un trabajo útil (por ejemplo, jugar una marcha o mostrar AlertView).

De todo el código TextEdit, solo debe tenerse en cuenta que el campo debe tener cuidado para establecer la propiedad " isValid " correctamente y extraer el método " Verified ()"De su delegado. Sin embargo, tenga en cuenta que el campo de entrada no utiliza una referencia al objeto administrador, sino una colección. Esto le permite vincular un campo de entrada a varios administradores.

Por consiguiente, cada uno de los delegados deberá extraer el método.

    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()
        }
    }

Ahora, si necesita crear un nuevo formulario con campos de entrada, ni siquiera necesita establecer valores de propiedad personalizados: será suficiente copiar los atributos de tiempo de ejecución necesarios en masa y aplicarlos a un nuevo campo (no olvide simplemente reemplazar el nombre de la clase).


En términos generales, el truco que usa el "objeto" en el encabezado del formulario puede usarse mucho más ampliamente que solo para la validación de campo: reacciona con MVP a MVVM sin ningún Rx. Su uso más común es el uso compartido de la red y la notificación de cambios en el modelo CoreData.

All Articles