0Pricing
Swift Academy · Урок

Связывание слоёв без фреймворка DI

Объединяйте объекты в точке входа приложения с помощью шаблона корня композиции.

«Связывание слоёв без фреймворка DI» — бесплатный урок Swift Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Корень композиции

Корень композиции — это единственное место, где создаются и связываются все объекты. В приложении SwiftUI им обычно служит @main.

@main
struct MyApp: App {
  // All wiring happens here
  private let container = AppContainer()
  var body: some Scene {
    WindowGroup { container.makeRootView() }
  }
}

Шаблон AppContainer

Структура или класс AppContainer создаёт граф объектов, скрывая сложность связывания от структуры приложения.

final class AppContainer {
  let db = SQLiteDatabase()
  lazy var userRepo: UserRepository = RemoteUserRepository(db: db)
  lazy var fetchUser = FetchUserUseCase(repo: userRepo)
  lazy var profileVM = ProfileViewModel(useCase: fetchUser)
  func makeRootView() -> some View { ProfileView(viewModel: profileVM) }
}

Отложенные свойства для правильного порядка

Используйте свойства lazy, чтобы зависимости создавались в правильном порядке без ручного управления последовательностью.

final class Container {
  lazy var network: NetworkClient = URLSessionClient()
  lazy var api: APIService = APIService(client: network)  // created after network
  lazy var repo: ItemRepository = RemoteItemRepository(api: api)
}

Фабричные методы

Добавьте в контейнер фабричные методы для создания объектов уровня представления с зависимостями, специфичными для каждого экрана.

extension AppContainer {
  func makeOrderFlow() -> OrderFlowView {
    let repo = RemoteOrderRepository(api: api)
    let useCase = PlaceOrderUseCase(repo: repo)
    let vm = OrderViewModel(useCase: useCase)
    return OrderFlowView(viewModel: vm)
  }
}

Значения окружения для внедрения

В SwiftUI используйте собственные EnvironmentKey, чтобы внедрять зависимости глубоко в дерево представлений без последовательной передачи свойств.

private struct FetchUserKey: EnvironmentKey {
  static let defaultValue: FetchingUser = FetchUserUseCase(repo: NullUserRepo())
}
extension EnvironmentValues {
  var fetchUser: FetchingUser {
    get { self[FetchUserKey.self] } set { self[FetchUserKey.self] = newValue }
  }
}

Использование ключа окружения

Внедряйте зависимость через .environment(\.fetchUser, container.fetchUser), а в представлениях считывайте её с помощью @Environment(\.fetchUser).

ContentView()
  .environment(\.fetchUser, container.fetchUser)

// In a deep view:
@Environment(\.fetchUser) private var fetchUser

Контейнеры с областью действия

Создавайте дочерние контейнеры для областей действия функциональных возможностей: они наследуют общие зависимости, но владеют собственными зависимостями этой функциональной возможности.

final class CheckoutContainer {
  let cart: CartRepository
  let payment: PaymentService
  lazy var placeOrder = PlaceOrderUseCase(cart: cart, payment: payment)
  init(parent: AppContainer) {
    cart = parent.cartRepo
    payment = parent.paymentService
  }
}

Тестирование корня композиции

Тестируйте фабричные методы контейнера, проверяя, что возвращаемые объекты имеют правильный тип и конфигурацию.

func testContainerBuildsProfileView() {
  let container = AppContainer(db: InMemoryDatabase())
  let view = container.makeRootView()
  XCTAssertTrue(type(of: view) == ProfileView.self)
}

Предотвращение циклических зависимостей

Если A зависит от B, а B зависит от A, добавьте посредника или перестройте обязанности, чтобы разорвать цикл.

// Circular:
// UserService → NotificationService → UserService
// Fix: UserService → NotificationInput (protocol) ← NotificationService

Когда стоит использовать фреймворк DI

Ручное связывание хорошо подходит для приложений среднего размера. Рассматривайте фреймворки (Needle, Swinject), только когда контейнер становится слишком большим для сопровождения.

// Manual: fine for <20 top-level dependencies
// Framework: helps with large teams, 50+ services, code-generation for factories

Пример для повторения

Полный пример связывания в небольшом приложении: контейнер создаёт все зависимости, а фабрика создаёт корневое представление.

final class AppContainer {
  private let db = CoreDataStack.shared
  lazy var userRepo: UserRepository = LocalUserRepository(db: db)
  lazy var fetchUser = FetchUserUseCase(repo: userRepo)
  func makeContentView() -> ContentView {
    ContentView(viewModel: ProfileViewModel(useCase: fetchUser))
  }
}

Быстрая проверка

Что такое корень композиции в приложении Swift?

Итоги урока

Связывайте приложение в корне композиции (обычно @main). Используйте AppContainer со свойствами lazy для правильного порядка создания. Добавляйте фабричные методы для графов зависимостей отдельных экранов. Внедряйте глубокие зависимости через собственные EnvironmentKey. Разрывайте циклические зависимости с помощью протоколов-посредников.

Часто задаваемые вопросы

Урок «Связывание слоёв без фреймворка DI» бесплатный?

Да — полный текст урока «Связывание слоёв без фреймворка DI» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Связывание слоёв без фреймворка DI»?

Объединяйте объекты в точке входа приложения с помощью шаблона корня композиции. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Связывание слоёв без фреймворка DI»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Слои: предметная область, данные и представление
  2. Шаблоны сценария использования и репозитория
  3. Инверсия зависимостей с абстракциями протоколов
  4. Связывание слоёв без фреймворка DI
← Назад к Swift Academy