View

In the view layer, we originally had a QuestionViewresponsible for printing the question in the console, as well as a PromptView. Both can still live in our new model. They had simple interfaces, and were completely stateless, as follows:

struct QuestionView {
func show(question: Question) {
print(question.question)
}
}

struct PromptView {
func show() {
print("> ", terminator: "")
}
}

We also have ViewController. This class is our main entry point for the View layer. It will keep its responsibilities, ask the questions, gain user input features, and bind the viewModel. We can call it MainView:

class MainView {
private let questionView = QuestionView()
private let promptView = PromptView()

Initialization will now require to pass ViewModel. Often, in the MVVM pattern, the viewModel is attached to the following: 

    let viewModel: ViewModel
init(viewModel: ViewModel) {
self.viewModel = viewModel
bindViewModel()
}

Binding ViewModel is the core of the implementation. As it is event-driven, the implementation will require us to set the closures on the viewModel object. In response to the events that are sent by viewModel, View will update and print the appropriate information:

    func bindViewModel() {

The onQuestionChanged handler contains a bit of logic, as viewModel represents the end of the game when it feeds a nil question to the view. It gives the opportunity to view to display a final message:

        viewModel.onQuestionChanged = { [unowned self] in
guard let string = self.viewModel.getQuestionText() else {
// No more questions?
self.finishPlaying()
return
}
self.ask(question: string)
}

The onAnswer handler is very straightforward. A question has been answered by the user, and viewModel has determined that the answer wasn't right. Use isGood: Bool to determine whether the program should congratulate the user or tell them that their answer was inaccurate, as follows:

        viewModel.onAnswer = { [unowned self] (isGood) -> Void in
if isGood {
self.goodAnswer()
} else {
self.badAnswer()
}
}
}

The rest of the implementation for this class is similar to the one in the MVC example:

    private func ask(question: Question) {
questionView.show(question: question)
promptView.show()
}

func goodAnswer() { /* implement me */ }
func badAnswer() { /* implement me */ }
func finishPlaying() { /* implement me */ }
}

This completes the refactoring of our game, using the MVVM pattern. As you have seen, the responsibilities have shifted around. The view binds itself on a ViewModel, completely isolating it from the rest of the program. The model layer is still identical, which indicates that we did a great job in our refactoring.

Using the new program is straightforward, as well:

// Create a new ViewModel instance
let viewModel = ViewModel()
// Inject the viewModel into the view
let view = View(viewModel: viewModel)
// Start the viewModel
viewModel.start()

By starting the viewModel, the events will start to fire and the view will update, prompting the user for questions.