diff --git a/Classes/ValidationManager.swift b/Classes/ValidationManager.swift index c8d8ee4..2d7c1e6 100644 --- a/Classes/ValidationManager.swift +++ b/Classes/ValidationManager.swift @@ -16,6 +16,7 @@ class ValidationManager { var validationUnits = [String:ValidationUnit]() var valid:Bool = false + var identifierCounter = 0 func registerTextField(textField:UITextField, validationTypes:[ValidatorType]=[], identifier:String?) -> ValidationUnit { @@ -34,7 +35,8 @@ class ValidationManager { func registerObject(object:AnyObject, validationTypes:[ValidatorType]=[], objectNotificationType:String, initialText:String, identifier:String?) -> ValidationUnit { - var unit_identifier:String = identifier ?? "\(self.validationUnits.count+1)" + // if no identifier passed in, generate one + let unit_identifier:String = identifier! ?? self.generateIdentifier() // create validation unit with passed-in types and store a reference let unit:ValidationUnit = ValidationUnit(validatorTypes: validationTypes, identifier: unit_identifier, initialText: initialText) @@ -52,6 +54,31 @@ class ValidationManager { } + func addUnit(unit:ValidationUnit, identifier:String?) -> String { + + // if an identifier is passed in, that is used instead of the unit's identifier property + // if no identifier passed in and no identifier found on the unit, generate one + let unit_identifier:String = (identifier! ?? unit.identifier) ?? self.generateIdentifier() + + self.validationUnits[unit_identifier] = unit + + // listen for validation updates from unit + NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("unitUpdateNotificationHandler:"), name: ValidationUnitUpdateNotification, object: unit) + + return unit_identifier + } + + + func removeUnitForIdentifier(identifier:String) { + + // remove validation update listener for this unit + let unit = self.unitForIdentifier(identifier) + NSNotificationCenter.defaultCenter().removeObserver(self, name: ValidationUnitUpdateNotification, object: unit) + + self.validationUnits.removeValueForKey(identifier) + } + + func dealloc() { NSNotificationCenter.defaultCenter().removeObserver(self) } @@ -67,6 +94,13 @@ class ValidationManager { } + func generateIdentifier() -> String { + let identifier = "\(self.identifierCounter++)" + + return identifier + } + + func checkValidationForText() { for (key, unit) in self.validationUnits { @@ -80,7 +114,7 @@ class ValidationManager { var is_valid:Bool = true for (key, unit) in self.validationUnits { - if (!unit.valid) { + if (unit.enabled && !unit.valid) { is_valid = false break } diff --git a/Classes/ValidationTypes/ValidatorEmailType.swift b/Classes/ValidationTypes/ValidatorEmailType.swift index 881ba23..4b8c148 100644 --- a/Classes/ValidationTypes/ValidatorEmailType.swift +++ b/Classes/ValidationTypes/ValidatorEmailType.swift @@ -16,6 +16,9 @@ class ValidatorEmailType:ValidatorType { self.valid = false + // while Unicode characters are permissible in user and domain sections of an e-mail address, they must be encoded and use IDNA. + // (see: http://en.wikipedia.org/wiki/Unicode_and_e-mail#Unicode_support_in_message_headings ) + // this validation does not parse or check thusly-encoded strings for well-formedness (yet?) if let regex = NSRegularExpression(pattern: "^[+\\w\\.\\-'!#$%&*+-/=?^_`{|}~]+@[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+$", options: .CaseInsensitive, error: &error) { let num_matches:Int = regex.numberOfMatchesInString(text, options: .ReportProgress, range: NSMakeRange(0, text.utf16Count)) diff --git a/Classes/ValidationUnit.swift b/Classes/ValidationUnit.swift index efe16e1..a527b09 100644 --- a/Classes/ValidationUnit.swift +++ b/Classes/ValidationUnit.swift @@ -17,6 +17,7 @@ class ValidationUnit { var errors = [String:[String]]() var identifier = "" var valid:Bool = false + var enabled:Bool = true let validationQueue:dispatch_queue_t var lastTextValue:String = "" @@ -28,7 +29,6 @@ class ValidationUnit { self.identifier = identifier self.lastTextValue = initialText - for type:ValidatorType in self.registeredValidationTypes { if (type.sendsUpdates) { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("validationUnitStatusUpdatedNotification:"), name: ValidatorUpdateNotification, object: type) @@ -77,26 +77,32 @@ class ValidationUnit { func validateText(text:String) { - dispatch_async(self.validationQueue, { - - var num_valid = 0 - - for type:ValidatorType in self.registeredValidationTypes { - let is_valid:Bool = type.isTextValid(text) - num_valid += Int(is_valid) - } - - let type_count:Int = self.registeredValidationTypes.count - (num_valid == type_count) ? (self.valid = true) : (self.valid = false) - - self.lastTextValue = text - - // send notification (on main queue, there be UI work) - dispatch_async(dispatch_get_main_queue(), { - self.validationComplete() + if (self.enabled) { + dispatch_async(self.validationQueue, { + [weak self] in + + if let strong_self = self { + + var num_valid = 0 + + for type:ValidatorType in strong_self.registeredValidationTypes { + let is_valid:Bool = type.isTextValid(text) + num_valid += Int(is_valid) + } + + let type_count:Int = strong_self.registeredValidationTypes.count + (num_valid == type_count) ? (strong_self.valid = true) : (strong_self.valid = false) + + strong_self.lastTextValue = text + + // send notification (on main queue, there be UI work) + dispatch_async(dispatch_get_main_queue(), { + strong_self.validationComplete() + }) + } + }) - - }) + } } @@ -135,17 +141,21 @@ class ValidationUnit { @objc func validationUnitStatusUpdatedNotification(notification:NSNotification) { - if let user_info = notification.userInfo { - if let status_num:NSNumber = user_info["status"] as? NSNumber { - let is_valid: Bool = status_num.boolValue ?? false - - if (is_valid) { - self.validateText(self.lastTextValue) - } else { - self.valid = false - self.validationComplete() + if (self.enabled) { + + if let user_info = notification.userInfo { + if let status_num:NSNumber = user_info["status"] as? NSNumber { + let is_valid: Bool = status_num.boolValue ?? false + + if (is_valid) { + self.validateText(self.lastTextValue) + } else { + self.valid = false + self.validationComplete() + } } } + } } diff --git a/Demo/PapersPlease/ViewController.swift b/Demo/PapersPlease/ViewController.swift index 5d9d52c..0cbdcf0 100644 --- a/Demo/PapersPlease/ViewController.swift +++ b/Demo/PapersPlease/ViewController.swift @@ -27,7 +27,7 @@ class ViewController: UIViewController { self.validationUnit = ValidationUnit(validatorTypes: unit_validator_types, identifier: "email") NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("validationUnitStatusChange:"), name: ValidationUnitUpdateNotification, object: self.validationUnit) - self.validationUnit.validateText("nico@somewhere") + self.validationUnit.validateText("you@somewhere") let length_type:ValidatorLengthType = ValidatorLengthType(minimumCharacters:3, maximumCharacters:20)