Как взаимодействуют компоненты в паттерне MVC (Model-View-Controller)?

«Как взаимодействуют компоненты в паттерне MVC (Model-View-Controller)?» — вопрос из категории Архитектура, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В классическом MVC (как он часто реализуется в Cocoa/Cocoa Touch) взаимодействие происходит по принципу "Controller как посредник".

Роли компонентов:

  • Model: Представляет данные и бизнес-логику. Не имеет ссылок на View или Controller. Уведомляет об изменениях (через KVO, делегаты или уведомления).
  • View: Пассивный слой отображения. Отображает данные, полученные от Controller, и передает пользовательские события (тапы, ввод) обратно в Controller.
  • Controller (ViewController): Координатор. Получает события от View, обрабатывает их, обновляет Model и, в ответ на изменения Model, обновляет View.

Схема потока данных:

   [Действие пользователя]
          ↓
      [Controller] ←------ (обновляет) ------ [Model]
          |                                       |
    (обновляет)                            (уведомляет об изменениях)
          |                                       |
          ↓                                       ↓
      [View]                                 [Controller] → (обновляет) → [View]

Пример на UIKit:

// Model
struct Task {
    var title: String
    var isCompleted: Bool
}

// View (настроена в Storyboard/XIB или кодом)
// Содержит UILabel и UIButton. Кнопка подключена к @IBAction в Controller.

// Controller
class TaskViewController: UIViewController {
    @IBOutlet weak var titleLabel: UILabel!
    var task: Task! // Model

    override func viewDidLoad() {
        super.viewDidLoad()
        updateView() // Начальная настройка View на основе Model
    }

    @IBAction func toggleCompletion(_ sender: UIButton) {
        // Обработка события от View, изменение Model
        task.isCompleted.toggle()
        updateView() // Обновление View на основе измененной Model
    }

    private func updateView() {
        // Controller обновляет View данными из Model
        titleLabel.text = task.title
        titleLabel.textColor = task.isCompleted ? .gray : .black
    }
}

Основная проблема (Massive ViewController): Controller становится "мусорным ведром" для логики отображения, сетевых запросов, валидации данных и навигации, что затрудняет тестирование и поддержку.