Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

RDSDataSource: Мастер-класс по Dip

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Dip

YouTube-Videos werden auf SlideShare nicht mehr unterstützt.

Original auf YouTube ansehen

2014 - Typhoon >>>> 2016 - Dip
Nächste SlideShare
New Design of OneRing
New Design of OneRing
Wird geladen in …3
×

Hier ansehen

1 von 41 Anzeige

RDSDataSource: Мастер-класс по Dip

Herunterladen, um offline zu lesen

Илья Пучка, один из создателей DI-фреймворка Dip, рассказал о его устройстве и основных фичах. В программе доклада:
- Как работать с Dip, основные фичи, на что стоит особенно обращать внимание.
- Некоторые особенные фичи Dip, которых нет в других контейнерах
- Какие проблемы вызывает изначально выбранный в Dip дизайн API, какие могут быть альтернативы, какие их плюсы и минусы
- Кодогенератор, который может упростить жизнь

RDSDataSource - внутренние пятничные митапы iOS-команды RAMBLER&Co.

Илья Пучка, один из создателей DI-фреймворка Dip, рассказал о его устройстве и основных фичах. В программе доклада:
- Как работать с Dip, основные фичи, на что стоит особенно обращать внимание.
- Некоторые особенные фичи Dip, которых нет в других контейнерах
- Какие проблемы вызывает изначально выбранный в Dip дизайн API, какие могут быть альтернативы, какие их плюсы и минусы
- Кодогенератор, который может упростить жизнь

RDSDataSource - внутренние пятничные митапы iOS-команды RAMBLER&Co.

Anzeige
Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Andere mochten auch (16)

Anzeige

Ähnlich wie RDSDataSource: Мастер-класс по Dip (20)

Weitere von RAMBLER&Co (15)

Anzeige

Aktuellste (20)

RDSDataSource: Мастер-класс по Dip

  1. 1. Dip
  2. 2. 2014 - Typhoon >>>> 2016 - Dip
  3. 3. h"ps://github.com/AliSo3ware/Dip
  4. 4. 1. Создаём контейнеры 2. Регистрируем в них ВСЕ компоненты 3. Резолвим граф
  5. 5. 1. Создаём контейнеры
  6. 6. class AppDelegate { let container = DependencyContainer(configBlock: configureContainers) } func configureContainers(root: DependencyContainer) { _ = moduleA ... } let moduleA = DependencyContainer() { container in ... } ...
  7. 7. 1 модуль - 1 контейнер
  8. 8. moduleA.collaborate(with: moduleB, root) moduleB.collaborate(with: moduleA, root)
  9. 9. 2. Регистрируем в них ВСЕ компоненты
  10. 10. container.register(.unique) { ServiceImp() as Service } |_____| |___________| |_______| scope конструктор регистрируемый тип
  11. 11. container.register(.unique, type: Service, factory: ServiceImp.init) |_____| |_______| |______________| scope регистрируемый конструктор тип
  12. 12. container.register(.unique) { ServiceImp() } container.register(.unique, factory: ServiceImp.init)
  13. 13. Constructor injec-on container.register() { try ServiceImp( repository: container.resolve() ) as Service }
  14. 14. Property injec-on container.register() { let service = ServiceImp() service.repository = try container.resolve() as ServiceRepository return service as Service } //или container.register() { ServiceImp() as Service } .resolvingProperties { container, service in service.repository = try container.resolve() as ServiceRepository }
  15. 15. Аргументы container.register() { (url: NSURL) in ServiceImp(url: url) as Service } container.register() { ServiceImp(repository: $0) as Service }
  16. 16. enum ComponentScope { case unique case shared //default case singleton case eagerSingleton case weakSingleton }
  17. 17. 3. Резолвим граф
  18. 18. let service = try! container.resolve() as Service let service = try! container.resolve(arguments: NSURL(...)) as Service let repository = try! container.resolve() as ServiceRepository let service = try! container.resolve(arguments: repository) as Service
  19. 19. Сториборды 1. import DipUI 2. extension ViewController: StoryboardInstantiatable { } 3. container.register(tag: "myVC") { ViewController() } 4. DependencyContainer.uiContainers = [container]
  20. 20. Отличия от других контейнеров
  21. 21. Auto-wiring class ServiceImp: Service { init(repository: Repository) { ... } } container.register() { ServiceImp(repository: $0) as Service } //или container.register(Service.self, factory: ServiceImp.init) container.register() { RepositoryImp() as Repository } let service = try! container.resolve() as Service
  22. 22. Auto-injec+on class ServiceImp: Service { let repository = Injected<Repository>() } container.register() { ServiceImp() as Service } container.register() { RepositoryImp() as Repository } let service = try! container.resolve() as Service
  23. 23. Op#onals class ServiceImp: Service { init(repository: Repository?) { ... } } container.register() { ServiceImp(repository: $0) as Service } container.register() { RepositoryImp() as Repository } let service = try! container.resolve() as Service
  24. 24. Type forwarding class ServiceImp: ServiceA, ServiceB { ... } container.register() { ServiceImp() as ServiceA } .implements(ServiceB.self) .implements(ServiceC.self) container.resolve() as ServiceA --> ServiceImp container.resolve() as ServiceB --> ServiceImp try! container.resolve() as ServiceC //fatal error
  25. 25. Achtung !
  26. 26. Achtung 1 container.register() { ServiceImp() as ServiceA } .implements(ServiceB.self) container.register() { ServiceImp1() as ServiceA } container.register() { ServiceImp2() as ServiceB } container.resolve() as ServiceA --> ServiceImp1 container.resolve() as ServiceB --> ServiceImp2
  27. 27. Achtung 2 class ServiceImp: Service { init(url: NSURL?) { ... } } container.register() { (url: NSURL?) in ServiceImp(url: url) as Service } let url: NSURL = ... try! container.resolve(arguments: url) as Service //fatal error let url: NSURL? = ... try! container.resolve(arguments: url) as Service
  28. 28. Achtung 3 extension ViewController: StoryboardInstantiatable { } DependencyContainer.uiContainers = [container] Создавать контейнер до didFinishLaunching, в идеале в init AppDelegate
  29. 29. Проблемы register/resolve API
  30. 30. pros • типичное API • сториборды cons • слабая типизация, хоть и на дженериках • бойлерплейт при оборачивании в интерфейс фабрики • сложная реализация - пришлось изобретать auto-wiring и type-forwarding
  31. 31. Альтернатива (см. h'ps://github.com/jkolb/FieryCrucible) class Module: DependencyFactory { func wireframe() -> ModuleWireframe { shared( factory: { Wireframe() as ModuleWireframe }, configure: { wireframe in wireframe.interactor = self.interactor() } } func interactor() -> ModuleInteractor { shared({ Interactor() as ModuleInteractor }) ... } }
  32. 32. pros • Упрощает API • Упрощает реализацию • Фабричный интерфейс из коробки • Более читаемо cons • cториборды
  33. 33. Кодогенератор h"ps://github.com/ilyapuchka/dipgen
  34. 34. /** @dip.register Service */ class ServiceImp: Service { }
  35. 35. Dip.base.swi* let baseContainer = DependencyContainer { container in unowned let container = container container.register(factory: ServiceImp.init) } class BaseFactory { private let container: DependencyContainer init(container: DependencyContainer = baseContainer) { self.container = container } func service() -> Service { return container.resolve() } }
  36. 36. /** @dip.factory List @dip.constructor init(nibName:bundle:) */ class ListViewController: UIViewController { /**@dip.arguments nibName*/ override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
  37. 37. Dip.list.swi) let listContainer = DependencyContainer { container in unowned let container = container container.register(factory: { nibName in try ListViewController.init(nibName: nibName, bundle: container.resolve()) }) } class ListFactory { private let container: DependencyContainer init(container: DependencyContainer = listContainer) { self.container = container } func listViewController(nibName nibNameOrNil: String?) -> ListViewController { return try! container.resolve(arguments: nibNameOrNil) } }
  38. 38. implements TypeName, ... - вторичные типы factory Name - имя фабрики name Name - имя фабричного метода inject [TypeName] - тип свойства tag, scope, storyboardInstantiatable и др.
  39. 39. • дополнительная документация • легко синхронизировать с кодом • ошибки видны при компиляции • генерирует весь необходимый бойлерплейт
  40. 40. !

×