Skip to content

Latest commit

 

History

History
102 lines (91 loc) · 13.2 KB

migration1to2.md

File metadata and controls

102 lines (91 loc) · 13.2 KB

Миграция с версии 1.x.x на версию 2.x.x

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

Новые возможности

  • Удален DynamicAssembly, за место него теперь позднее связывание - можно разделить объявление и реализацию интерфейса.
  • Автоматическая поддержка области видимости у компонентов
  • Проверка альтернативных типов во время компиляции - которые задавались через asType
  • Добавлено описание ошибок за место ихнего обычного вывода
  • Добавлена поддержка стека вызова -> теперь при правильном использовании можно узнать не только причину, но и место откуда было вызвано, и какие типы были созданы в середине.
  • Сильна улучшена автоматика при регистрации. Теперь можно напрямую передавать init функцию, и получать готовые значения для внедрения через свойствам.
  • Добавлен weak single
  • Добавлена возможность синхронизации двух контейнеров, так чтобы они имели одни и теже объекты с областью видимости perScope
  • Улучшено деление на части - если вы чтото не используете, это можно не включать в проект.
  • Поддержка автоматического внедрения через свойства класса. Работает только для наследников от NSObject
  • Сильное изменение синтаксиса, на более краткий и понятный

Если эти возможности не являются для вас критичными, и проект не планируется развиваться еще очень долго, то не стоит проводить миграцию.

Разделение в cocoapods

Начну пожалуй с установки. Теперь весь проект делиться на составные части:

  • Core
  • Description
  • Component
  • Module
  • Storyboard
  • Scan
  • RuntimeArgs

По умолчанию устанавливаются следующие части: Core, Description, Component, Module, Storyboard. По этой причине, если вы использовали возможности сканирования, или передачу аргументов во время исполнения, то стоит включить эти части при установке. Для упрощения подобной ситуации, существует отдельно выделенная часть: Full - в неё включаются все остальные части. Пример использования: pod 'DITranquillity/Description' - установить поддержку описания pod 'DITranquillity/Module' - установить поддержку модулей Ядро включается всегда

Переименования

Начну с самой главной части - переименования.

При регистрации типа

Название самой функции также претерпело изменения: register() -> register(type:) - но если вы использовали closure, то это изменение вас не коснется.

  • initializer -> initial
  • dependency -> injection
  • asType -> as (также см. ниже)
  • initializerDoesNotNeedToBe -> initialNotNecessary
  • asSelf -> as(.self)
  • asName -> set(name:)
  • asDefault- > set(.default)
  • initial(byNib:) -> initial(nib:)
  • initial(byStoryboard:) -> initial(useStoryboard:)

Сборки, модули, компоненты

Я окончательно отошел от именования принятого у тайфуна, и назвал вещи своими именами.

  • DIModule -> DIComponent
  • DIAssembly -> DIModule
  • publicModules, internalModules -> components (также см. ниже)
  • register(module:) -> register(component:)
  • register(assembly:) -> register(module:) Обращаю внимание на пересечение имен, поэтому обязательно переменуйте вначале модуль в компонент, дабы избежать коллизий имен.

Удаленные возможности

  • Регистрация типа с runtime аргументами через функцию register. см. ниже
  • Инициалицизая типа с runtime аргументами через функцию initial. Теперь существует всего одна возможность это сделать: функция initialWithArg.
    Причина: сложность понимания когда используются рантайм аргументы, а когда обычное внедрение. И достаточная редкость использования рантайм аргументов.
  • DILazy который появился в версии 1.3.1.
    Причина: Противоречие концепции библиотеки - нужно использовать "настоящее внедрениее зависимостей"
  • *! и **!
    Причина: Исключения возникающие внутри операций должны прокидываться наверх. Данные операции правоцируют на игнорирование ошибки, и падению в месте где возникла проблема, что не всегда удобно.

Расширение старых возможностей

  • Передача init функции при использовании метода register(type:) или initial().
    Пример: builder.register(type: YourClass.init(p1:p2:)
  • Внедрение свойств без использования контейнера.
    Пример: .injection { $0.value = $1 } или .injection { obj, value in obj.value = value }
  • Обязательная! проверка альтернативного типа во время компиляции: as(YourProtocol.self).check{$0}. Так как старое использование не обязывало в функции register указывать тип возращаемого объекта, хоть и было желательным, то существует способ проигнорировать проверку: as(YourProtocol.self).unsafe()
  • Функции register(type:), initial, injection, initialWithArg теперь пробрасывают исключения наверх. По этой причине настоятельно рекомендую убрать из них все try! и заменить на обычный try.
  • Область видимости для компонент при использовании модулей. Очень важное расширение библиотеки, так как теперь библиотека самостоятельно следит чтобы небыло обращений из одного модуля в другой. Это накладывает ограничения, из-за которых старый код может начать кидать исключения. При этом даже в новом коде не стоит переносить контейнер из модуля в модуль, то есть если создается контейнер в модуле Main то этот контейнер не должен покинуть этот модуль. Исключением пожалуй является только storyboard, но его корректной обработкой занимается сама библиотека. Если у вас маленький проект, в котором вы уверены, что никогда не будет пересечения имен, лучше перепишите весь код на обычные компоненты за место использования модулей. Да модули более выразительные, но они несут дополнительную смысловую нагрузку.

Новые возможности

  • Позднее связывание. Достаточно сложная возможность, являющаяся следствием из нормальной поддержки области видимости для компонент внутри модулей. В силу этого позднее связывание доступно только если используются модули. Подробно о нем можно прочитать в главах: Позднее связывание, Модули
  • Указание области видимости у компоненты: Теперь для указания области видимости по аналогии со старыми publicModules и internalModules, их нужно указывать у каждой компоненты отдельно. По умолчанию все компоненты используют internal. Для изменения на public у компоненты нужно написать следующий образом:
class YourComponent: DIComponent {
  var scope: DIComponentScope { return .public }
  func load(builder: DIContainerBuilder) ...
}

Также см.: Компоненты

  • По аналогии с другими DI контейнерами я добавил еще одну области видимости: .weakSingle. То есть объект живет, до тех пор пока не будут потеряны все ссылки на него, после чего он будет пересоздан. Подробно о времени жизни можно прочитать в главе: Время жизни
  • Автоматическое внедрение свойств. Эта возможность работает только для классов отнаследованных от NSObject. Причем наследоваться должен как класс хранящий свойства, так и сами свойства. Для указания факта, что вы хотите использовать автоматическое внедрение при регистрации типа нужно использовать функцию: useAutoPropertyInjection. У этой возможности есть два существенных плюса: Все внедрения проходят сами и появление нового свойства не заставляет его указывать в регистрации; Эти свойства можно объявить private и они всеравно смогут внедриться. То есть можно избежать проблем с инкапсулящией. Подробно об этой возможности можно прочитать в главе: Регистрация
  • Сокращенный синтаксис для регистрации storyboard, дабы не писать каждый раз DIStoryboard:
builder.register(type: UIStoryboard.self)
    .initial(name: "Main", bundle: nil)

Другое

  • Значительные правки в работе со storyboard - исправление багов и написание тестов для этой части
  • Автоматическое игнорирование включение одного и тогоже кода несколько раз. Если вы вызовете одну и туже функцию, в которой есть код регистрации, несколько раз то все отработает правильно - регистрация пройдет всего один раз.
  • Ошибки теперь имеют стек. Помимо этого у них появилось словестное описание.

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