Предпочтительным является использование delegate method
Общей частью работы программиста является синхронизация состояния пользовательского интерфейса с состоянием модели.и пользовательский ввод.когда пользователь взаимодействует с экраном.это взаимодействие должно быть немедленно отражено if it useful for user
не ждите, пока он сделает еще один шаг press submit Button
Позвольте нам объяснить это. Предположим, у вас есть экран с двумя входами, именем пользователя или адресом электронной почты и паролем в виде TextFields
и одна кнопка для входа в систему
- вам не нужно, чтобы пользователь нажимал кнопку входа в систему, прежде чем вводить его имя пользователя, пароль
- , вам нужно уведомить viewController о том, что пользователь вводит данные, и теперь он может отправить
вам необходимо выполнить некоторую проверку введенных пользователем данных, прежде чем разрешить отправку. Например, требуется проверка по номеру символа для проверки пароля и электронной почты ... и т. Д.
Первый подходбез делегата
Проверка не будет выполнена, мы сообщим пользователю об ошибке после того, как он нажмет кнопку входа, модель LoginView не будет ничего о ViewController при вводе пользователем, viewModel будет знать информацию только тогда, когда пользователь нажимает кнопку входа
Второй подход с делегатом
В этом подходе LoginViewModel теперь знает, что пользователь печатает, прежде чем он нажимает на кнопку входа, мы можем выполнить некоторые проверки, чтобы включить или отключить loginButton
ViewController:
class ViewController: UIViewController,LoginViewModelViewDelegate {
private var loginviewmodel = LoginViewModel()
@IBOutlet weak var textFieldUserName: UITextField!
@IBOutlet weak var textFieldPassword: UITextField!
@IBAction func signIn(_ sender: Any) {
loginviewmodel.performLogin()
}
override func viewDidLoad() {
super.viewDidLoad()
// delegate to allow ViewModel notify his view
loginviewmodel.viewDelegate = self
self.textFieldUserName.addTarget(self, action: #selector(userNameFieldDidChange(_:)), for: UIControlEvents.editingChanged)
self.textFieldPassword.addTarget(self, action: #selector(passwordFieldDidChange(_:)), for: UIControlEvents.editingChanged)
}
// MARK: - user Input notification
@objc func userNameFieldDidChange(_ textField: UITextField)
{
if let text = textField.text {
loginviewmodel.userName = text
}
}
@objc func passwordFieldDidChange(_ textField: UITextField)
{
if let text = textField.text {
loginviewmodel.password = text
}
}
// MARK: - LoginViewModel Delegate
func canSubmitStatusDidChange(_ viewModel: LoginViewModel, status: Bool) {
// Enable or disable login button to allow user to submit input
}
}
ViewModel:
import Foundation
protocol LoginViewModelViewDelegate: class
{
func canSubmitStatusDidChange(_ viewModel: LoginViewModel, status: Bool)
}
class LoginViewModel {
weak var viewDelegate: LoginViewModelViewDelegate?
fileprivate var passwordIsValidFormat: Bool = false
fileprivate var userNameIsValidFormat: Bool = false
/// Submit
var canSubmit: Bool {
return userNameIsValidFormat && passwordIsValidFormat
}
/// Email
var userName: String = "" {
didSet {
if oldValue != userName {
let oldCanSubmit = canSubmit
userNameIsValidFormat = validateUserNameAsEmailFormat(userName)
if canSubmit != oldCanSubmit {
viewDelegate?.canSubmitStatusDidChange(self, status: canSubmit)
}
}
}
}
/// Password
var password: String = "" {
didSet {
if oldValue != password {
let oldCanSubmit = canSubmit
passwordIsValidFormat = validatePasswordFormat(password)
if canSubmit != oldCanSubmit {
viewDelegate?.canSubmitStatusDidChange(self, status: canSubmit)
}
}
}
}
func performLogin() {
// perform Login and you can add anather delegate to notify View with error Message of login thow error
}
fileprivate func validateUserNameAsEmailFormat(_ userName: String) -> Bool
{
let REGEX: String
REGEX = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,32}"
return NSPredicate(format: "SELF MATCHES %@", REGEX).evaluate(with: userName)
}
/// Validate password is at least 6 characters
fileprivate func validatePasswordFormat(_ password: String) -> Bool
{
let trimmedString = password.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return trimmedString.count > 8
}
}