Связывание слоёв без фреймворка 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 — локальная установка не требуется.
Все уроки этого курса
- Слои: предметная область, данные и представление
- Шаблоны сценария использования и репозитория
- Инверсия зависимостей с абстракциями протоколов
- Связывание слоёв без фреймворка DI