Validation Layers


Since all the fields conform to the Field class, validation layers tied directly to the Fields has never been easier!

Lets define 3 fields, an EntryField, an AreaField, and a PickerField

let entryField = EntryField()
let areaField = AreaField()
let pickerField = PickerField()

Lets also define a CaseIterable enum:

extension CaseIterable where AllCases.Element: Equatable {
    static func make(index: Int) -> Self? { //get the key from the case index
        let a = Self.allCases
        if (index > a.count - 1) { return nil } //out of range
        return a[a.index(a.startIndex, offsetBy: index)]
    }

    func index() -> Int { //get the index from the case
        let a = Self.allCases
        return a.distance(from: a.startIndex, to: a.firstIndex(of: self)!)
    }
}

enum FieldKeys : String, CaseIterable {
  case entry
  case area
  case picker
}

With our CaseIterable enum we can use the validation keys as tags for the fields!

entryField.tag = FieldKeys.entry.index()
areaField.tag = FieldKeys.area.index()
pickerField.tag = FieldKeys.picker.index()

Lets say we need to validate a generic string (with the regex set in our core data model) before commiting changes to our model using an extension on NSManagedObject.

extension NSManagedObject {
  func validateString(view: Field, key: String){
      var value = view.text as AnyObject?
       do {
            try self.validateValue(&(value), forKey: key)
       } catch {
            view.setError(withText: "please try again")
            print(error)
            return
        }
        self.setValue(value, forKey: key)
  }
}

Now on any of the fields’ didEndEditing delegate methods we only need to 2 lines to validate our entry.

//EntryFieldDelegates
func entryFieldDidEndEditing(_ view: EntryField){
  //the key reconstructed from our enum used for the field tags
  gaurd let key = FieldKeys.make(index: view.tag) else {return}
  ourNSManagedObject.validateString(view,key.rawValue)
}

//AreaFieldDelegates
func areaFieldDidEndEditing(_ view: AreaField){
  //the key reconstructed from our enum used for the field tags
  gaurd let key = FieldKeys.make(index: view.tag) else {return}
  ourNSManagedObject.validateString(view,key.rawValue)
}

//PickerFieldDelegates
func pickerFieldDidEndEditing(_ view: PickerField){
  //the key reconstructed from our enum used for the field tags
  gaurd let key = FieldKeys.make(index: view.tag) else {return}
  ourNSManagedObject.validateString(view,key.rawValue)
}

We now have a validation layer capable of both data model validation and UI feedback!