Объедините текущие значения полей, считывайте их по tap через withLatestFrom и запускайте один запрос на вход, не завершая всю подписку при сетевой ошибке.
Создать механизм подписки
Объедините текущие значения полей, считывайте их по tap через withLatestFrom и запускайте один запрос на вход, не завершая всю подписку при сетевой ошибке.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Опишите, как бы вы спроектировали API, которое при нажатии на кнопку получает введённые пользователем данные из UITextField и отправляет их в сетевой запрос.
class ViewController: UIViewController {
@IBOutlet private var usernameField: UITextField!
@IBOutlet private var pwdField: UITextField!
@IBOutlet private var loginButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// ?
}
private func signInUser(login: String, password: String) -> Single<Void> {
// network request
}
}
Ответ
Объедините текущие значения полей, считывайте их по tap через withLatestFrom и запускайте один запрос на вход, не завершая всю подписку при сетевой ошибке.
Схема внутри viewDidLoad при наличии DisposeBag и импортов RxSwift/RxCocoa:
let credentials = Observable.combineLatest(
usernameField.rx.text.orEmpty,
pwdField.rx.text.orEmpty
)
loginButton.rx.tap
.withLatestFrom(credentials)
.filter { !$0.0.isEmpty && !$0.1.isEmpty }
.flatMapFirst { [weak self] pair -> Observable<Result<Void, Error>> in
guard let self else { return .empty() }
return self.signInUser(login: pair.0, password: pair.1)
.asObservable()
.map { Result<Void, Error>.success($0) }
.catch { .just(.failure($0)) }
}
.observe(on: MainScheduler.instance)
.subscribe(onNext: { result in
// Обновить интерфейс успеха или ошибки по result.
})
.disposed(by: disposeBag)
flatMapFirst игнорирует повторные нажатия, пока запрос активен. Ошибка превращается в отдельный результат внутри запроса, поэтому следующий tap работает. Пароль не логируют; серверная валидация обязательна независимо от проверки пустых строк.
Источник: github.com.