← Назад к вопросам

Что не следует добавлять в Coordinator?

2.0 Middle🔥 151 комментариев
#UIKit и верстка

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что не следует добавлять в Coordinator

Coordinator (координатор) — это паттерн проектирования, который отвечает за управление потоком навигации и бизнес-логикой переходов между экранами в iOS-приложении. Он отделяет ответственность за навигацию от UIViewController, что улучшает модульность, тестируемость и поддержку кода. Однако важно понимать, что координатор — это не "мусорное ведро", куда можно сбрасывать любую логику. Его следует использовать строго по назначению.

Основные ошибки при реализации Coordinator

1. Бизнес-логика (Business Logic)

Координатор не должен содержать логику обработки данных, вычислений, сетевых запросов или работы с базой данных. Это ответственность сервисов, менеджеров, интеракторов (в архитектуре VIPER) или ViewModel (в MVVM). Координатор лишь инициирует переходы на основе результатов этой логики, полученных от других компонентов.

// ❌ НЕПРАВИЛЬНО: Coordinator занимается бизнес-логикой
class ProfileCoordinator {
    func fetchUserData() {
        APIManager.shared.fetchUser { [weak self] result in
            switch result {
            case .success(let user):
                self?.updateUI(with: user) // Смешивание логики и навигации
            case .failure:
                self?.showError()
            }
        }
    }
}

// ✅ ПРАВИЛЬНО: Координатор делегирует бизнес-логику сервису
class ProfileCoordinator {
    let userService: UserServiceProtocol

    func showProfile() {
        userService.fetchUser { [weak self] result in
            switch result {
            case .success(let user):
                self?.showProfileScreen(user: user) // Только навигация
            case .failure(let error):
                self?.showErrorScreen(error: error)
            }
        }
    }
}

2. UI-логика и Data Source

Координатор не должен управлять элементами интерфейса, такими как наполнение таблиц (UITableViewDataSource), обновление UIView, анимации или обработка жестов. Это зона ответственности ViewController или View. Координатор может передавать данные в экран, но не должен заниматься их отображением.

// ❌ НЕПРАВИЛЬНО: Coordinator выступает как dataSource
class ListCoordinator: NSObject, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count // Нарушение разделения ответственности
    }
}

// ✅ ПРАВИЛЬНО: ViewController или отдельный объект управляют UI
class ListViewController: UIViewController {
    var dataSource: ListDataSource!
    // ...
}

3. Состояние приложения (App State)

Координатор не должен хранить глобальное состояние приложения (например, текущий пользователь, токены авторизации, настройки). Для этого существуют синглтоны, менеджеры состояний, Keychain или решения вроде Redux/SwiftUI State Management. Координатор может реагировать на изменения состояния (например, переход на экран логина при разлогине), но не быть его источником.

4. Жизненный цикл ViewController

Не следует вмешиваться в методы жизненного цикла UIViewController, такие как viewDidLoad, viewWillAppear, viewDidDisappear. Эти методы должны оставаться в самом ViewController или в связанных с ним компонентах (например, ViewModel в MVVM). Координатор может получать уведомления о событиях (через делегаты или замыкания) для управления навигацией, но не переопределять их.

5. Прямые зависимости от фреймворков

Избегайте жёсткой привязки к конкретным фреймворкам (кроме UIKit/SwiftUI для базовой навигации). Координатор не должен содержать код работы с CoreData, Firebase, Alamofire и т.д. Вместо этого используйте инъекцию зависимостей (Dependency Injection), передавая абстракции (протоколы).

// ❌ НЕПРАВИЛЬНО: Прямая зависимость от Alamofire
import Alamofire

class AuthCoordinator {
    func login() {
        AF.request("https://api.example.com/login").response { ... } // Жёсткая связь
    }
}

// ✅ ПРАВИЛЬНО: Зависимость через протокол
protocol NetworkServiceProtocol {
    func login(completion: @escaping (Result<User, Error>) -> Void)
}

class AuthCoordinator {
    let networkService: NetworkServiceProtocol // Абстракция

    func login() {
        networkService.login { [weak self] result in
            // Обработка результата для навигации
        }
    }
}

6. Управление памятью и ресурсами вне навигации

Координатор не должен заниматься освобождением ресурсов, не связанных напрямую с его жизненным циклом (например, отмена сетевых запросов, очистка кешей). Это задача соответствующих сервисов. Однако координатор обязан управлять памятью для дочерних координаторов и избегать циклов удерживания (retain cycles) через [weak self].

7. Жёсткая конфигурация UI

Избегайте прямой конфигурации UI-элементов (цвета, шрифты, констрейнты) внутри координатора. Используйте фабрики (Factory) или билдеры (Builder) для создания ViewController, либо передавайте параметры через инициализатор.

// ❌ НЕПРАВИЛЬНО: Координатор настраивает UI-элементы
class SettingsCoordinator {
    func createSettingsViewController() -> UIViewController {
        let vc = SettingsViewController()
        vc.button.backgroundColor = .red // Нарушение принципа единственной ответственности
        return vc
    }
}

// ✅ ПРАВИЛЬНО: Использование фабрики или конфигуратора
class SettingsViewControllerFactory {
    static func create() -> SettingsViewController {
        let vc = SettingsViewController()
        vc.configure(with: .default) // Конфигурация внутри ViewController
        return vc
    }
}

Принципы, которым следует придерживаться

  • Единственная ответственность (Single Responsibility): Coordinator управляет только навигацией.
  • Инъекция зависимостей (Dependency Injection): Передавайте сервисы через инициализатор.
  • Слабая связность (Loose Coupling): Координатор не должен знать о внутренней реализации экранов.
  • Протоколо-ориентированный подход: Используйте протоколы для абстракции.

Итог: Coordinator — это мощный паттерн для управления навигацией, но его сила в ограниченной и чёткой ответственности. Добавление лишней логики превращает его в "God Object", что усложняет тестирование, поддержку и нарушает архитектурные принципы. Сфокусируйтесь на том, чтобы координатор был "дирижёром", который управляет переходами, а не выполняет всю работу за оркестр.

Что не следует добавлять в Coordinator? | PrepBro