Как обновить переменную в MVVM? - PullRequest
0 голосов
/ 30 ноября 2018

Я пытаюсь использовать MVVM.Я собираюсь на VC2 от VC1.Я обновляю viewModel.fromVC = 1, но значение не обновляется в VC2.

Вот что я имею в виду:

Есть viewModel, в нем естьvar fromVC = Int().Теперь, в vc1, я называю viewModel как

let viewModel = viewModel().

Теперь при нажатии кнопки я обновляю viewModel.fromVC = 8.И, переходя к следующему экрану.На следующем экране, когда я печатаю fromVC, тогда я получаю значение как 0 вместо 8.

Вот как VC2 выглядит как

class VC2 {

    let viewModel = viewModel()

    func abc() {
        print(viewModel.fromVC)
    }

}

Теперь явызов abc() в viewDidLoad и fromVC печатается как 0 вместо 8. Любая помощь?

1 Ответ

0 голосов
/ 30 ноября 2018

Для шаблона MVVM вы должны понимать, что это слой, разделенный на 2 части: входы и выходы.

В терминах входных данных ваша viewModel должна перехватывать каждое событие из viewController, идля выходов это способ, которым viewModel будет отправлять данные (правильно отформатированные) в viewController.

Так что, в принципе, если у нас есть viewController, подобный этому:

final class HomeViewController: UIViewController { 

    // MARK: - Outlets

    @IBOutlet private weak var titleLabel: UILabel!

    // MARK: - View life cycle

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK: - Actions

    @IBAction func buttonTouchUp(_ sender: Any) {
         titleLabel.text = "toto"
    }
}

Нам нужночтобы извлечь обязанности для viewModel, так как viewController обрабатывает событие touchUp и владеет данными для переноса на метку.

Извлекая это, вы сохраняете ответственность правильно, и, в конце концов, вы 'Я смогу правильно протестировать вашу viewModel ?

Так как это сделать?Легко, давайте взглянем на нашу будущую viewModel:

final class HomeViewModel {

    // MARK: - Private properties

    private let title: String

    // MARK: -  Initializer

    init(title: String) {
        self.title = title
    }

    // MARK: - Outputs

    var titleText: ((String) -> Void)?

    // MARK: - Inputs

    func viewDidLoad() {
        titleText?("")
    }

    func buttonDidPress() {
        titleText?(title)
    }
}

Итак, теперь, выполняя это, вы сохраняете различные обязанности, давайте посмотрим, как связать нашу viewModel с нашим предыдущим viewController:

final class HomeViewController: UIViewController { 

    // MARK: - public var

    var viewModel: HomeViewModel!

    // MARK: - Outlets

    @IBOutlet private weak var titleLabel: UILabel!

    // MARK: - View life cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        bind(to: viewModel)

        viewModel.viewDidLoad()
    }

    // MARK: - Private func

    private func bind(to viewModel: HomeViewModel) {
        viewModel.titleText = { [weak self] title in
            self?.titleLabel.text = title
        }
    }

    // MARK: - Actions

    @IBAction func buttonTouchUp(_ sender: Any) {
         viewModel.buttonDidPress()
    }
}

Итак, одна вещь отсутствует, вы спросите меня «а как инициализировать нашу viewModel внутри viewController?»

По сути, вы должны еще раз извлечь обязанности, у вас может быть Screensслой, который будет отвечать за создание вида следующим образом:

final class Screens {

    // MARK: - Properties

    private let storyboard = UIStoryboard(name: StoryboardName, bundle: Bundle(for: Screens.self))


    // MARK: - Home View Controller

   func createHomeViewController(with title: String) -> HomeViewController {
        let viewModel = HomeViewModel(title: title)
        let viewController = storyboard.instantiateViewController(withIdentifier: "Home") as! HomeViewController
        viewController.viewModel = viewModel
        return viewController
    }
}

И, наконец, сделайте что-то вроде этого:

let screens = Screens()
let homeViewController = screens.createHomeViewController(with: "Toto")

Но основной задачей было предоставить возможность протестировать егоправильно, так как это сделать?очень просто!

import XCTest
@testable import mvvmApp

final class HomeViewModelTests: XCTestCase {

    func testGivenAHomeViewModel_WhenViewDidLoad_titleLabelTextIsEmpty() {
        let viewModel = HomeViewModel(title: "toto")
        let expectation = self.expectation("Returned title")

        viewModel.titleText = { title in
            XCTAssertEqual(title, "")
            expectation.fulfill()
        }

        viewModel.viewDidLoad()

        waitForExpectations(timeout: 1.0, handler: nil)
    }

    func testGivenAHomeViewModel_WhenButtonDidPress_titleLabelTextIsCorrectlyReturned() {
        let viewModel = HomeViewModel(title: "toto")
        let expectation = self.expectation("Returned title")

        var counter = 0
        viewModel.titleText = { title in
            if counter == 1 {
                XCTAssertEqual(title, "toto")
                expectation.fulfill()
            }
            counter += 1
        }

        viewModel.viewDidLoad()

        viewModel.buttonDidPress()

        waitForExpectations(timeout: 1.0, handler: nil)
    }
}

И это все ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...