如何使用RxSwift实现邮箱验证功能?
Hey there! Let's figure out how to implement email validation with RxSwift, using the username validation example you already have as a blueprint.
First, let's make sure we're on the same page with the ValidationResult enum you're using (I'm assuming it looks something like this, since your username example references it):
enum ValidationResult { case empty case validating case ok(message: String) case failed(message: String) }
Step 1: Basic Local Email Validation
This mirrors the structure of your validateUsername function, and covers the same rules as your old SwiftValidator setup (required field + valid email format):
func validateEmail(_ email: String) -> Observable<ValidationResult> { // Handle empty input (matches SwiftValidator's RequiredRule) if email.isEmpty { return .just(.empty) } // Validate email format (matches SwiftValidator's EmailRule) // We'll use a regex here, but you could also use NSDataDetector for more robust checks let emailPattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" let isValidFormat = NSPredicate(format: "SELF MATCHES %@", emailPattern).evaluate(with: email) guard isValidFormat else { return .just(.failed(message: "Invalid email")) } // If you don't need to check if the email is already registered, return success here return .just(.ok(message: "Email format is valid")) }
Step 2: Add Remote Validation (If Needed)
If you also need to verify that the email isn't already registered (like your username check against the API), extend the function to include that call:
func validateEmail(_ email: String) -> Observable<ValidationResult> { if email.isEmpty { return .just(.empty) } let emailPattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" let isValidFormat = NSPredicate(format: "SELF MATCHES %@", emailPattern).evaluate(with: email) guard isValidFormat else { return .just(.failed(message: "Invalid email")) } let loadingState = ValidationResult.validating // Replace with your actual API call that returns an Observable<Bool> (true = email available) return API.emailAvailable(email) .map { isAvailable in isAvailable ? .ok(message: "Email is available") : .failed(message: "Email already registered") } .startWith(loadingState) }
Step 3: Bind It to Your UI
Just like you'd use SwiftValidator to update error labels, you can bind the validation result to your email text field and error label:
// Assuming you have these properties set up @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var emailErrorLabel: UILabel! let disposeBag = DisposeBag() // In viewDidLoad or setup emailTextField.rx.text.orEmpty .flatMapLatest { [weak self] email in // Use flatMapLatest to cancel previous validation calls if the user types quickly self?.validateEmail(email) ?? .just(.empty) } .subscribe(onNext: { result in switch result { case .empty: self.emailErrorLabel.text = "" case .validating: self.emailErrorLabel.text = "Checking..." self.emailErrorLabel.textColor = .gray case .ok(let message): self.emailErrorLabel.text = message self.emailErrorLabel.textColor = .green case .failed(let message): self.emailErrorLabel.text = message self.emailErrorLabel.textColor = .red } }) .disposed(by: disposeBag)
This setup directly replaces your old SwiftValidator code:
RequiredRule()is handled by checking if the email string is emptyEmailRule(message: "Invalid email")is covered by our regex format check
内容的提问来源于stack exchange,提问作者Sam Shaikh

