Rx Swift: проверка сложных текстовых полей

Я новичок в RxSwift и все примеры, которые я нашел, относятся к простым случаям.

Я пытаюсь сделать проверку формы для моих текстовых полей. Мой пользовательский класс TextField имеет метод isValid() и regexp, isValid возврат основан на regexp приписывать.

До сих пор я написал следующее:

let valids = [mLastName, mFirstName, mEmailField].map {
    $0.rx.text.map {
        text -> Bool in
        // I want more complex logic here
        // Like return field.isValid()
        return text!.characters.count > 0
    }
}    

let _ = Observable.combineLatest(valids) { iterator -> Bool in
    return iterator.reduce(true, { $0 && $1 })
}.subscribe(onNext: { allValid in
    ///update button according to AllValid
})

Кто-нибудь знает, как обновить код для базы первым Observable<Bool> основываться на моем isValid() метод вместо text!.characters.count

2 ответа

Решение

Я нашел ответ сам. Проблема была в первой карте, я не должен использовать анонимный параметр.

Увидеть:

let valids = [mLastName, mFirstName, mEmailField].map { field in
    field.rx.text.map({ _ in return field.isValid() })
}

_ = Observable.combineLatest(valids) { iterator -> Bool in
    return iterator.reduce(true, { return $0 && $1 })
}.bindTo(self.mValidateButton.rx.isEnabled)

Вероятно, есть много способов сделать это.

Ты можешь использовать filter преобразовывать rx.text Наблюдаемый в вашем пользовательском классе TextField:

var isTextValid: Observable<Bool> {
    return rx.text.filter { _ in 
        return self.isValid()
    }
}

тогда вы можете объединить isTextValid из всех текстовых полей с combineLatest,


Вы также можете извлечь логику проверки из настраиваемого текстового поля (возможно, вам даже не нужно настраиваемое текстовое поле вообще).

Выгоды:

  • проверка может быть проще для модульного теста
  • вы можете легко повторно использовать проверку в разных местах вашего приложения (например, для UITextView если ты когда-нибудь им воспользуешься).

Проект класса валидатора:

class TextValidator {
    var input: Observable<String>
    var regex: NSRegularExpression

    init(input: Observable<String>, regex: NSRegularExpression) {
       self.input = input
       self.regex = regex
    }

    func validate() -> Observable<Bool> {
        return input.map { text in 
             //return true if regex matches the text
        }
    }       
}

Тогда вы можете использовать его следующим образом:

let mailValidator = TextValidator(input: mLastName.rx.text, regex: /* actual regex*/)
let firstNameValidator = TextValidator(input: mFirstName.rx.text, regex: ...)



let _ = Observable.combineLatest(mailValidator.validate(), firstName.validate(), ...) 
// and so on

Теперь, если вы хотите написать модульные тесты для валидаторов (что вы, вероятно, должны сделать), вы можете просто пройти Observable.just("Some value") как input в TextValidator и убедитесь, что Observable возвращается validate() делает.

Другие вопросы по тегам