Using model controllers

Just as we have controllers dedicated to managing views—the view controllersyou should consider using controllers to help communicate with complex model layers. Code bases that suffer from Massive View Controller syndrome often exhibit the following pathologies in their view controllers:

Let's first start with an interface for a message composer that exhibits Massive View Controller syndrome:

class MassiveViewController : UIViewController {

var textView = UITextView()
var sendButton = UIButton()

override func viewDidLoad() {
super.viewDidLoad()
/* layout the views */
/* design the views */
}

func sendTapped(sender: UIButton) {
if textView.text.count == 0 {
// display error
} else {
postMessage(message: textView.text) { (success, error) in
if success {
// all good
} else if let error = error {
// Show an error alert
}
}
}
}

struct BooleanResponse: Codable {
let success: Bool
}

struct MessageRequest: Codable {
let message: String
}

private func postMessage(message: String,
callback: @escaping (Bool, Error?) -> Void) {
let messagePayload = MessageRequest(message: message)
var request = URLRequest(url: postMessageAPIURL)
request.httpMethod = "POST"
do {
try request.httpBody = JSONEncoder().encode(messagePayload)
} catch let error {
callback(false, error)
return
}

URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
callback(false, error)
} else if let data = data {
do {
let result = try JSONDecoder().decode(BooleanResponse.self, from: data)
callback(result.success, nil)
} catch let error {
callback(false, error)
}
}
}
}
}

In the preceding code example, we have the following issues:

As all the code is set into a view controller, when this controller grows in features and design it will quickly become unmaintainable. Let's refactor with the following goals in mind: