Настройка Dependency Injection (Swinject) в iOS-приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Настройка Dependency Injection (Swinject) в iOS-приложении
Средний
~2-3 дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Настройка Dependency Injection с Swinject в iOS-приложении

Swinject — один из наиболее зрелых DI-контейнеров для Swift. Использовался широко до эпохи SwiftUI, сейчас продолжает применяться в UIKit-проектах и смешанных кодовых базах, где SwiftUI существует рядом с UIKit. Если проект на чистом SwiftUI — смотрите в сторону Factory или нативного @Environment. Для UIKit-архитектур с MVVM, VIPER или Clean Architecture Swinject остаётся актуальным выбором.

Базовая настройка контейнера

Точка сборки всего графа зависимостей — Container. Типичная организация: AppAssembly протокол + отдельные Assembly-классы по модулям:

import Swinject

class NetworkAssembly: Assembly {
  func assemble(container: Container) {
    container.register(URLSession.self) { _ in
      URLSession(configuration: .default)
    }.inObjectScope(.container)  // синглтон в рамках контейнера

    container.register(APIClient.self) { r in
      DefaultAPIClient(session: r.resolve(URLSession.self)!)
    }.inObjectScope(.container)
  }
}

class AuthAssembly: Assembly {
  func assemble(container: Container) {
    container.register(AuthRepository.self) { r in
      DefaultAuthRepository(
        apiClient: r.resolve(APIClient.self)!,
        keychain: r.resolve(KeychainService.self)!
      )
    }
    container.register(AuthViewModel.self) { r in
      AuthViewModel(repository: r.resolve(AuthRepository.self)!)
    }
  }
}

Инициализация в AppDelegate или SceneDelegate:

let assembler = Assembler([
  NetworkAssembly(),
  KeychainAssembly(),
  AuthAssembly(),
  ProfileAssembly()
])
let container = assembler.resolver

Где ломается чаще всего

Force unwrap при resolve. r.resolve(SomeService.self)! — стандартный паттерн в Swinject, но при пропущенной регистрации это краш в рантайме. Альтернатива: использовать Container.loggingBehavior = .verbose в debug-сборках — тогда незарегистрированные зависимости выводятся в лог до краша. Для критичных зависимостей используем safeResolve с проверкой в applicationDidFinishLaunching:

func validateRegistrations(_ container: Container) {
  assert(container.resolve(APIClient.self) != nil, "APIClient not registered")
  assert(container.resolve(AuthRepository.self) != nil, "AuthRepository not registered")
}

ObjectScope и утечки памяти. .container (синглтон) держит объект на всё время жизни контейнера. Для ViewModel в UIKit это проблема: если ViewModel зарегистрирована в .container и держит сильную ссылку на ViewController — утечка. ViewModel регистрируем в .transient (новый объект на каждый resolve) или .graph (единственный объект в рамках одного дерева resolve).

Circular dependencies. Если AuthViewModel зависит от Router, а Router зависит от AuthViewModel — Swinject уходит в бесконечную рекурсию при resolve. Решается через initCompleted callback для разрыва цикла:

container.register(AuthViewModel.self) { _ in AuthViewModel() }
  .initCompleted { r, vm in
    vm.router = r.resolve(Router.self)
  }

Интеграция с UIKit Navigation

Swinject хорошо работает с Coordinator-паттерном. Координатор получает resolver и сам разрешает зависимости при создании экранов:

class AuthCoordinator {
  private let resolver: Resolver
  init(resolver: Resolver) { self.resolver = resolver }

  func showLogin() {
    let vm = resolver.resolve(AuthViewModel.self)!
    let vc = LoginViewController(viewModel: vm)
    navigationController.pushViewController(vc, animated: true)
  }
}

Что входит в работу

  • Настройка Container и Assembler с разбивкой на модульные Assembly
  • Регистрация всех слоёв: сеть, репозитории, ViewModel, сервисы
  • Правильные ObjectScope для каждого типа
  • Интеграция с Coordinator или Router
  • Валидация регистраций в debug-режиме
  • Документация графа зависимостей

Сроки

2–3 дня для типичного проекта с 30–50 регистрируемыми типами. Стоимость зависит от текущей архитектуры и объёма рефакторинга.