From d7986ee3c3694ca3b3fbed02f9d12d2b2e4bb54e Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Thu, 27 Nov 2025 15:40:14 +0400 Subject: [PATCH] feat: add validationResult property to UI validation flow --- .../ValidatorUI/Classes/IUIValidatable.swift | 28 ++++++++++++++++++- .../FormFieldManager/FormFieldManager.swift | 1 - 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Sources/ValidatorUI/Classes/IUIValidatable.swift b/Sources/ValidatorUI/Classes/IUIValidatable.swift index 283bbcf..f8012be 100644 --- a/Sources/ValidatorUI/Classes/IUIValidatable.swift +++ b/Sources/ValidatorUI/Classes/IUIValidatable.swift @@ -26,6 +26,12 @@ public protocol IUIValidatable: AnyObject { /// The input value that needs to be validated. var inputValue: Input { get } + /// The most recent validation result, if any. + /// + /// This value is updated automatically when calling `validate(rules:)`. + /// Implementations may use this property to drive UI updates. + var validationResult: ValidationResult? { get } + /// Validates the input value using a single rule. /// /// - Parameter rule: A validation rule conforming to `IValidationRule`. @@ -48,9 +54,10 @@ public protocol IUIValidatable: AnyObject { // MARK: - Associated Object Keys -// Keys used for storing associated objects (validation rules and handlers) +// Keys used for storing associated objects (validation rules, handlers, and a validation result) private nonisolated(unsafe) var kValidationRules: UInt8 = 0 private nonisolated(unsafe) var kValidationHandler: UInt8 = 0 +private nonisolated(unsafe) var kValidationResult: UInt8 = 0 // Validator instance shared for UI validation // swiftlint:disable:next prefixed_toplevel_constant @@ -78,6 +85,7 @@ public extension IUIValidatable { func validate(rules: [any IValidationRule]) -> ValidationResult { let result = validator.validate(input: inputValue, rules: rules) validationHandler?(result) + validationResult = result return result } @@ -88,6 +96,24 @@ public extension IUIValidatable { validationRules.append(rule) } + /// The most recent validation result, if any. + /// + /// This value is updated automatically when calling `validate(rules:)`. + /// Implementations may use this property to drive UI updates. + private(set) var validationResult: ValidationResult? { + get { + (objc_getAssociatedObject(self, &kValidationResult) as? AnyObject) as? ValidationResult + } + set { + objc_setAssociatedObject( + self, + &kValidationResult, + newValue as ValidationResult?, + .OBJC_ASSOCIATION_RETAIN_NONATOMIC + ) + } + } + /// The array of validation rules associated with this UI element. var validationRules: [any IValidationRule] { get { diff --git a/Sources/ValidatorUI/Classes/SUI/Managers/FormField/FormFieldManager/FormFieldManager.swift b/Sources/ValidatorUI/Classes/SUI/Managers/FormField/FormFieldManager/FormFieldManager.swift index 31105cf..c276722 100644 --- a/Sources/ValidatorUI/Classes/SUI/Managers/FormField/FormFieldManager/FormFieldManager.swift +++ b/Sources/ValidatorUI/Classes/SUI/Managers/FormField/FormFieldManager/FormFieldManager.swift @@ -40,7 +40,6 @@ public final class FormFieldManager: IFormFieldManager { /// The manager subscribes to the validator's publisher so that any changes /// in validation results automatically trigger re-evaluation of the form's overall validity. public func append(validator: some IFormValidationContainer) { - // Subscribe to validation updates for this field validator .publisher .sink(receiveValue: { [weak self] _ in