哪个是从viewcontroller传递值到viewmodel的更好方法

时间:2018-06-01 10:55:12

标签: ios swift mvvm parameter-passing uitextfielddelegate

这个问题可能看起来很基本,但我发帖是为了得到建议。

以下是使用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 :(得分:1)

我更喜欢第二种情况

loginviewmodel.performLogin()

通过使用委托,您还可以在用户输入时验证两个文本字段中的输入,而不是等待用户输入错误数据然后验证

答案 1 :(得分:1)

首选是使用delegate method

程序员工作的一个常见部分是保持UI状态与Model状态同步。和用户输入。当用户与屏幕交互时。这种互动应该立即反映if it useful for user不要等到他再迈出一步press submit Button

让我们解释一下 假设您的屏幕有2个输入,用户名或电子邮件和密码为TextFields

和一个登录按钮

  • 在输入用户名,密码
  • 之前,您不需要用户按登录按钮
  • 您需要通知viewController该用户输入数据,现在他可以提交
  • 您需要在允许提交之前对用户输入数据进行一些验证。例如,需要验证密码和电子邮件验证的字符数等...

    没有代表的第一种方法

    没有验证只会在我按下登录后通知用户错误信息,LoginView Model在用户输入时没有关于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
    }

}

<强>视图模型:

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
    }


}

答案 2 :(得分:0)

请使用此:

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).")
    }
}