Какой будет лучший способ передать значения в viewmodel из viewcontroller - PullRequest
0 голосов
/ 01 июня 2018

Этот вопрос может показаться базовым, но я выкладываю его для получения предложений.

Ниже приведен пример модуля входа в систему с использованием шаблона MVVM.

Код viewcontroller выглядит следующим образом.

class ViewController: UIViewController {

    private var loginviewmodel = LoginViewModel()

    @IBOutlet weak var textFieldUserName: UITextField!

    @IBOutlet weak var textFieldPassword: UITextField!

    @IBAction func signIn(_ sender: Any) {
        //CASE 1
        loginviewmodel.performLogin(name: textFieldUserName.text!, pwd: textFieldPassword.text!)
        //CASE 2
        //loginviewmodel.performLogin()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        textFieldUserName.delegate = self
        textFieldPassword.delegate = self
    }
}

extension ViewController: UITextFieldDelegate {

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        let inputText = (textField.text! as NSString).replacingCharacters(in: range, with: string)

        switch textField {
        case textFieldUserName:
            loginviewmodel.updateUsername(inputText: inputText)
        case textFieldPassword:
            loginviewmodel.updatePassword(inputText: inputText)
        default:
            return false
        }      

        return true
    }
}

И код модели представления выглядит следующим образом.

class LoginViewModel {

    var userName: String?
    var password: String?

    func updateUsername(inputText: String) {
        self.userName = inputText
    }

    func updatePassword(inputText: String) {
        self.password = inputText
    }

    func performLogin() {
        print("Login successful with username = \(userName) and password = \(password).")
    }

    func performLogin(name: String, pwd: String) {
        print("Login successful with username = \(name) and password = \(pwd).")
    }

}

У меня есть два случая, когда значения передаются из viewcontroller в viewmodel по-разному.

  • Первый случай, когда тексты передаются непосредственно в качестве параметров функции

  • Второй случай, когда тексты передаются с помощью метода текстового делегата

Какой путь предпочтительнее здесь?

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Пожалуйста, используйте это:

class ViewController: UIViewController {
    private var loginviewmodel = LoginViewModel()

    @IBOutlet weak var textFieldUserName: UITextField!
    @IBOutlet weak var textFieldPassword: UITextField!

    @IBAction func signIn(_ sender: Any) {
        //CASE 1 
        // Check validation textfield is empty or not  
        loginviewmodel.performLogin(name: textFieldUserName.text!, pwd: textFieldPassword.text!)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        textFieldUserName.delegate = self
        textFieldPassword.delegate = self
    }
}

class LoginViewModel {
    var userName: String?
    var password: String?

    func performLogin(name: String, pwd: String) {
        print("Login successful with username = \(name) and password = \(pwd).")
    }
}
0 голосов
/ 01 июня 2018

Предпочтительным является использование 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
    }


}
0 голосов
/ 01 июня 2018

Я бы предпочел второй случай

loginviewmodel.performLogin()

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

...