Just as we have controllers dedicated to managing views—the view controllers—you 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:
- Network calls, logic, and parsing
- Caches, data stores, or Core Data logic
- Business logic or validators
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:
- The content validation is done at the view controller level
- The network logic, encoding, and decoding
- The error handling
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:
- The view controller should be responsible for view handling and exposing its state
- Network calls should be extracted to their own controller
- Validation should be extracted, as more rules may be added later