Validasi bidang iOS - cepat dan mudah

gambarValidasi bidang input mungkin merupakan tugas paling umum dalam aplikasi seluler. Setiap aplikasi yang berbentuk otorisasi dan registrasi juga memiliki sejumlah alat input dari pengguna, yang menimbulkan kesedihan yang diharapkan - kecanggihan canggih para penguji. Komunitas pengembang yang maju dan kompeten secara teknis telah belajar cara menangani mereka secara efektif dengan menanamkan ekspresi reguler dalam kode sumber.

Sebagai aturan, ketika Anda perlu membatasi diri pada pendaftaran dan otorisasi, Anda tidak perlu melakukan upaya khusus untuk mencapai tujuan Anda - kode ditransfer dari satu proyek ke proyek lain, hampir tanpa perubahan apa pun. Dan, yang paling penting, tanpa menambah jam kerja untuk pemeliharaan lebih lanjut dari kode ini. Tetapi dunia tidak akan sesederhana itu jika bukan karena dorongan kreatif dari desainer UI / UX yang cenderung, bertentangan dengan tradisi yang sudah mapan, logika dan akal sehat, untuk menemukan cara-cara baru berinteraksi dengan pengguna akhir, menempatkan pada beberapa bentuk, menurut pendapat mereka, kontrol yang diperlukan, aksesibilitas yang tergantung pada serangkaian kondisi Cartesian untuk memeriksa validitas sejumlah besar bidang input dan kontrol kontrol lainnya. Sayangnya, situasi ini sulit disebut langka.

Iritasi pengembang tumbuh sebanding dengan seberapa sering ia harus melanggar prinsip KERING: di satu sisi, kebanggaan profesional tidak memungkinkan kompromi, dan di sisi lain, kode tempel-tempel adalah cara paling efektif untuk menghindari siklus pengujian yang panjang - debugging. Kode yang disalin secara monoton jauh lebih mudah dipelihara daripada "sepeda" unik yang diverifikasi secara ideologis. Pencarian untuk alternatif tidak hanya menyia-nyiakan kreativitas pengembang, tetapi juga menambahkan ketergantungan pada proyek.

Pada saat yang sama, iOS SDK menghadirkan beberapa fitur yang sangat diremehkan yang dengan mudah menskalakan banyak tugas yang terkait tidak hanya dengan validasi - pemrograman deklaratif sangat menyederhanakan kehidupan pengembang. Tentu saja, penulisnya tahu kubu kekasih yang keras kepalateman-teman yang menggunakan kode "murni", tetapi karena penulis artikel mulai mengembangkan antarmuka profesional dengan mengembangkan antarmuka grafis untuk MS DOS, tidak ada keinginan besar untuk membuang waktu membuat kelas sempurna lain, dan jika Anda dapat menggunakannya dengan nilai yang sama mouse - preferensi akan diberikan ke mouse. Dengan demikian, ini menguraikan bagaimana meminimalkan jumlah kode untuk mempercepat dan menyederhanakan proses pengembangan.

Penolakan:
, . . , โ€” .

Tugas minimum yang khas adalah sebagai berikut:

Ada bidang masuk dan kata sandi input, dan tombol otorisasi. Penting bahwa tombol otorisasi berubah status (dapat diaktifkan) tergantung pada apa yang terkandung dalam bidang input.

Versi yang sedikit lebih maju dari tugas ini terlihat seperti ini:

Kami memiliki bidang masukan email, kata sandi dan nomor telepon, serta dua tombol - pendaftaran dan permintaan kode SMS untuk telepon yang dimasukkan. Tombol registrasi hanya akan tersedia ketika data yang benar dimasukkan di masing-masing bidang. Dan tombol permintaan kode adalah ketika bidang nomor telepon valid.

Solusi khas- pembuatan bendera yang saling tergantung dengan menggabungkan pernyataan "jika" dan "beralih" dalam satu pengontrol tampilan. Kesulitan akan meningkat dengan jumlah kontrol yang terlibat dalam proses. Solusi yang jauh lebih maju adalah membuat mesin negara. Solusinya sangat bagus - tetapi memakan waktu, di samping itu, memiliki ambang masuk yang tinggi - dan ini tidak berarti apa yang ingin saya terapkan pada pengembang malas (AKA "benar").

Lema tentang pengembang yang malas
, , . (ยซ ยป ), , .

Gagasan umum yang diusulkan adalah sebagai berikut:

Ada kelas untuk bidang input dan kelas untuk manajer validasi. Kolom input diwarisi, seperti yang diharapkan, dari UITextField. Manajer validasi - yang diwarisi dari UIControl, berisi kumpulan elemen yang divalidasi (sama sekali tidak perlu menjadi keturunan UITextField) dan menerapkan pola "pengamat". Selain itu, ia bertindak sebagai manajer untuk kontrol lain yang harus mengubah status aksesibilitasnya ketika keadaan elemen tervalidasi berubah. Dengan kata lain, jika bidang tersebut berisi email yang tidak valid, tombol pendaftaran seharusnya tidak tersedia.



Field input validasi sendiri - mereka dapat menjawab pertanyaan apakah data yang terkandung di dalamnya valid dan mengubah statusnya. Beberapa pengembang lebih suka menggunakan kelas validator yang terpisah (dan turunannya) untuk memvalidasi bidang input, tetapi praktik ini membuat mustahil untuk sepenuhnya menikmati portabilitas deklaratif dan terukur dari kode. Penting bagi kami bahwa bidang input atau kontrol tervalidasi lainnya mendukung antarmuka sederhana dari formulir:

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

Untuk menambahkan validasi ke proyek Anda, Anda perlu menambahkan 4 file dari contoh yang ada di repositori GitHub .

  • Kelas DSTextField mengimplementasikan bidang input dengan indikasi proses validasi.
  • Kelas DSValidationManager adalah pengamat yang menyediakan fungsionalitas yang kita butuhkan.
  • Extension StringOptional + Utils - hanya berisi satu metode yang menggunakan ekspresi reguler untuk memeriksa apakah teks dari baris saat ini valid.
  • UIView + Layer hanyalah cara yang mudah untuk menambahkan bingkai dengan lebar tertentu ke setiap keturunan UIView.

Tegasnya, jika Anda ingin menerapkan validasi dengan cara yang sama untuk kontrol lain, maka kemungkinan besar Anda hanya perlu DSValidationManager. Sisanya hanya digunakan untuk kenyamanan Anda.

Proses validasi ditunjukkan dalam video (gif).


Seperti yang Anda lihat, sebelum input dimulai, bidang dalam kondisi default, dan validasi terjadi saat data dimasukkan. Jika Anda meninggalkan bidang sebelum validasi selesai, sebuah prasasti muncul di bidang yang memberitahukan kesalahan tersebut. Tombol registrasi tidak akan tersedia sampai kedua bidang menjadi valid.

Situasi serupa berkembang pada layar kedua (yang menjadi tersedia hanya setelah aktivasi pendaftaran). Tetapi pada layar kedua, validasi bidang dan tombol terjadi secara independen - tombol pendaftaran hanya tersedia jika semua bidang gagal. Pada saat yang sama, tombol pengiriman SMS sudah tersedia ketika bidang dengan nomor telepon valid.

Dan sekarang triknya:Seluruh proyek hanya berisi satu kelas untuk pengontrol tampilan, yang sama yang dibuat Xcode saat membuat proyek dari templat. Itu benar-benar kosong. Tetapi bahkan itu tidak digunakan. Ini tidak sulit untuk diverifikasi dengan bantuan operator.



Pembaca yang penuh perhatian memperhatikan bahwa di sebelah kanan responden adalah Obyek dari palet komponen Xcode standar. Untuk itu, parameter Kelas ditimpa oleh kelas DSValidationManager . Trik yang sama dilakukan untuk bidang input, dengan satu-satunya perbedaan adalah bahwa kelas DSTextField digunakan di sana .

Sekarang semua pemrograman kami turun ke langkah-langkah sederhana berikut:

  1. Kaitkan koleksi diverifikasiControls dari ValidationManager dengan bidang input.


  2. Kaitkan koleksi managedControls dari ValidationManager dengan tombol yang ingin Anda kelola.


  3. Kaitkan bidang input dalam arah yang berlawanan dengan ValidationManager, menjadikannya delegasi.

  4. Di bidang input, tetapkan ekspresi reguler untuk validasi dan pesan kesalahan, serta properti kustom dan standar lainnya melalui manajer Xcode standar. Pada prinsipnya, segala sesuatu kecuali ekspresi reguler dapat dibiarkan "apa adanya". Ini hanya mengharuskan Anda menggunakan keyboard, dan kemudian, hanya untuk menyalin-menempelkan formula dari tyrnet. Jika pesan kesalahan tidak ada, maka tidak akan ditampilkan di layar.


Kode DSValidationManager adalah primitif jelek.

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

Seperti yang Anda lihat, dia menerima pemberitahuan dari satu koleksi, dan menindaklanjuti koleksi lainnya.

Seorang pengamat menjadikannya properti yang bahkan tidak kami pertimbangkan dalam contoh ini. Anda dapat menyeret koneksi dari objek ValidationManager langsung ke controller, menambahkan acara di sana mirip dengan mengklik tombol, dan memproses keadaan manajer langsung di controller. Jika Anda benar-benar menginginkannya. Ini bisa bermanfaat jika Anda tidak hanya mengunci kontrol, tetapi juga melakukan pekerjaan yang bermanfaat (misalnya, bermain pawai atau tampilkan AlertView).

Dari semua kode TextEdit, harus dicatat hanya bahwa bidang harus berhati-hati untuk mengatur properti " isValid " dengan benar , dan tarik metode " diverifikasi ()"Dari delegasinya. Namun, perhatikan bahwa bidang input tidak menggunakan referensi ke objek manajer, tetapi koleksi. Ini memungkinkan Anda untuk mengikat bidang input ke beberapa manajer.

Oleh karena itu, metode ini perlu ditarik oleh masing-masing delegasi.

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

Sekarang, jika Anda perlu membuat formulir baru dengan bidang input, Anda bahkan tidak perlu menetapkan nilai properti khusus - itu akan cukup untuk menyalin atribut Runtime yang diperlukan secara massal dan menerapkannya ke bidang baru (jangan lupa hanya mengganti nama kelas).


Secara umum, trik menggunakan "objek" di form header dapat digunakan jauh lebih luas daripada hanya untuk validasi lapangan - ia bereaksi dengan MVP ke MVVM tanpa Rx. Penggunaannya yang paling umum adalah berbagi jaringan dan pemberitahuan perubahan dalam model CoreData.

All Articles