The controller layer

The main controller will be called GameController, because it manages everything about the current game.

It creates an instance of the QuestionController from the model layer, and an instance of a ViewController from the view layer:

class GameController {
private let questions = QuestionController()
private let view = ViewController()

private func waitForAnswer(question: Question) {
// Wait for user input
let result = readLine()
// Ask the model if answer is good
if question.isGoodAnswer(result: result) {
// Update the view
view.goodAnswer()
} else {
view.badAnswer()
}
}

func start() {
// From the model layer, get the next question
while let question = questions.next() {
// Display the question on screen
view.ask(question: question)
waitForAnswer(question: question)
}
view.finishPlaying()
}
}

It is now possible to run the game, as follows:

// main.swift
GameController().start()

With this implementation, we have fully achieved the MVC design pattern:

With this simple example, we were able to demonstrate the power of the MVC pattern in encouraging proper separation of concerns and isolation of components. We also learned that we can have ViewControllers that don't belong in the controller layer of the application, but in the view layer, instead. They are controllers, but their responsibilities do not extend outside of the view layer.

Often, we see UIViewController and NSViewController suffer from Massive View Controller syndrome, as developers fail to realize this small but important detail. When view controllers grow and embed logic for the model layer, as well as take responsibility for complex view hierarchies, we get into the area of Massive View Controllers.

We can now move on to the specificities of UIViewController and NSViewController: how to use them efficiently, and how they fit into Swift programming for iOS and macOS.