Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion Sources/ValidatorUI/Classes/IUIValidatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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
Expand Down Expand Up @@ -78,6 +85,7 @@ public extension IUIValidatable {
func validate(rules: [any IValidationRule<Input>]) -> ValidationResult {
let result = validator.validate(input: inputValue, rules: rules)
validationHandler?(result)
validationResult = result
return result
}

Expand All @@ -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<Input>] {
get {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down